/*
* Datei: ZeichenModusEA.java
* Autor(en): Lukas K�nig
* Java-Version: 6.0
* Erstellt (vor): 24.11.2008
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/
package fmg.fmg8.graphVis.zeichenModi;
import fmg.fmg8.graphVis.DargestellterGraph;
import fmg.fmg8.graphVis.graph.Knoten;
import fmg.fmg8.sonstiges.SonstMeth;
import fmg.fmg8.statistik.Parametersatz;
import fmg.fmg8.umgebung2D.Vektor2D;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Point;
import java.awt.Polygon;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Klasse zum Erzeugen von geometrischen Figuren in Pfeilform.
* <P>
* Wenn eine Objektliste zur�ckgegeben wird, enth�lt diese Polygone,
* die fertig gezeichnet werden k�nnen und folgenderma�en codierte Strings:
* Drei aufeinanderfolgende Listenelemente bezeichnen:
* 1. Als Integer-Objekt die x-Koordinate,
* 2. Als Integer-Objekt die y-Koordinate und
* 3. Als String-Objekt den auszugebenden Text.
* z. B. liste = Pol, Pol, X-Koor, Y-Koor, String, Pol, ...
* ^^^^^^^^^^^^^^^^^^^^^^
* |---String-Objekt----|
*
* @author Lukas K�nig
*/
public class PfeilMaster implements Serializable {
/**
* Die Serial Version ID (generiert am 25. April 2007).
*/
private static final long serialVersionUID = -4051109731656095692L;
/**
* Gibt an, wie lang die Pfeilspitze (absolut) ist.
*/
private double pfeilSpLaenge;
/**
* Gibt die Pfeildicke absolut in Pixeln an.
*/
private int pfeilDicke;
/**
* Der aktuelle darzustellende Graph.
*/
private DargestellterGraph aktGraph;
/**
* Durchmesser von Knoten.
*/
private double knotenDurchm;
/**
* Liste der bereits in einer Richtung dargestellten Doppelkanten.
*/
private ArrayList<Polygon> dopp;
/**
* Speichert die Zuordnung der Kanten im Graphen...
*/
private ArrayList<Polygon> urspKanten;
/**
* ...zu den tats�chlich berechneten Ursprungs- und Ziel-Koordinaten.
*/
private ArrayList<Polygon> echteKant;
/**
* Parameter.
*/
private Parametersatz pars;
/**
* Einfacher Abschluss, also ohne Spitze.
*/
public static final Polygon2D EINFACHER_ABSCHLUSS
= PfeilMaster.erzeugeKonstanteEnden(0);
/**
* Einfache Spitze.
*/
public static final Polygon2D EINFACHE_SPITZE_1
= PfeilMaster.erzeugeKonstanteEnden(1);
/**
* Einfache Spitze.
*/
public static final Polygon2D EINFACHE_SPITZE_2
= PfeilMaster.erzeugeKonstanteEnden(4);
/**
* Einfache Spitze.
*/
public static final Polygon2D EINFACHE_SPITZE_3
= PfeilMaster.erzeugeKonstanteEnden(5);
/**
* Doppelspitzes Ende.
*/
public static final Polygon2D DOPPELSPITZES_ENDE
= PfeilMaster.erzeugeKonstanteEnden(2);
/**
* Kugeliges Ende.
*/
public static final Polygon2D KUGEL_ENDE
= PfeilMaster.erzeugeKonstanteEnden(3);
/**
* Kugeliges Ende.
*/
public static final Polygon2D RUECK_PFEIL
= PfeilMaster.erzeugeKonstanteEnden(6);
/**
* Erzeugt einige vordefinierte Endentypen.
* 0 = Gerades Ende.
* 1 = Normale Pfeilspitze 1.
* 2 = Doppelspitzes Ende.
* 3 = Kugel-Ende.
* 4 = Normale Pfeilspitze 2.
* 5 = Normale Pfeilspitze 3.
* 6 = R�ckbez�gliche Pfeilspitze.
*
* @param nummer Die Nummer des Endentyps.
*
* @return Eine Liste mit Punkten, die diesen Endentyp beschreiben.
*/
private static Polygon2D erzeugeKonstanteEnden(final int nummer) {
Vektor2D v;
Polygon2D a = null;
if (nummer == 0) {
a = new Polygon2D(0);
}
if (nummer == 1) {
a = new Polygon2D(3);
v = new Vektor2D(1.8, -0.7);
a.add(v);
v = new Vektor2D(0, 5);
a.add(v);
v = new Vektor2D(-1.8, -0.7);
a.add(v);
}
if (nummer == 2) {
a = new Polygon2D(1);
v = new Vektor2D(Vektor2D.NULL_VEKTOR);
v.sub(new Vektor2D(0, 0.3));
a.add(v);
}
if (nummer == 3) {
a = fmg.fmg8.graphVis.zeichenModi.Geometrie2D.bezierKurve(
new Vektor2D(0.5, 0),
new Vektor2D(5, 5),
new Vektor2D(-5, 5),
new Vektor2D(-0.5, 0),
0.0001);
}
if (nummer == 4) {
a = new Polygon2D(3);
v = new Vektor2D(1.8, 0);
a.add(v);
v = new Vektor2D(0, 7);
a.add(v);
v = new Vektor2D(-1.8, 0);
a.add(v);
}
if (nummer == 5) {
a = new Polygon2D(6);
v = new Vektor2D(2.3, -1.7);
a.add(v);
v = new Vektor2D(2.85, -1.7);
a.add(v);
v = new Vektor2D(0, 1.1);
a.add(v);
v = new Vektor2D(-2.85, -1.7);
a.add(v);
v = new Vektor2D(-2.3, -1.7);
a.add(v);
}
if (nummer == 6) {
Parametersatz params = new Parametersatz(new String[0]);
params.ergaenze();
PfeilMaster zeichnen = new PfeilMaster(params);
ArrayList<Double> dicken = new ArrayList<Double>();
Polygon2D bez = new Polygon2D();
for (double i = 0.5 * Math.PI; i <= Math.PI * 1.5; i += 0.001) {
bez.add(new Vektor2D(
-(Math.sin(i) * 4 - Math.sin(0.5 * Math.PI) * 4),
-(Math.cos(i) * 4 - Math.cos(0.5 * Math.PI) * 4)));
}
for (double i = 0; i < bez.size(); i += 1) {
dicken.add(1.0);
}
a = zeichnen.segmentPfeilPol2D(
bez,
dicken,
PfeilMaster.EINFACHER_ABSCHLUSS,
PfeilMaster.EINFACHE_SPITZE_1,
new Vektor2D(1, 1),
new Vektor2D(0.75, 0.75));
}
return a;
}
/**
* Konstruktor, der alle Attribute mit den als Parameter �bergebenen
* Werten initialisiert.
*
* @param pfD Pfeildicke (absolut in Pixeln).
* @param pfSpL Pfeilspitzenl�nge (absolut in Pixeln).
* @param stDicke Dicke der zur Pfeilrichtung senkrechten SkalenStriche.
* @param stLaenge L�nge der zur Pfeilrichtung senkrechten Skalenstriche.
* @param knDurchm Durchmesser von Knoten.
* @param par Die Parameter.
*/
public PfeilMaster(final int pfD,
final double pfSpL,
final double stDicke,
final double stLaenge,
final double knDurchm,
final Parametersatz par) {
this.pfeilDicke = pfD;
this.pfeilSpLaenge = pfSpL;
this.knotenDurchm = knDurchm;
this.aktGraph = null;
this.dopp = new ArrayList<Polygon>();
this.urspKanten = new ArrayList<Polygon>();
this.echteKant = new ArrayList<Polygon>();
this.pars = par;
}
/**
* Konstruktor, der alle Attribute mit den Werten aus der Klasse
* Konstanten initialisiert.
*
* @param par Die Parameter.
*/
public PfeilMaster(final Parametersatz par) {
this(Konstanten.PFEIL_DICKE,
Konstanten.PFEILSP_LAENGE,
Konstanten.STRICH_DICKE,
Konstanten.STRICH_LAENGE,
Konstanten.KN_DURCHM,
par);
}
/**
* Gibt die Eckpunkte eines Polygons zur�ck, das einen Pfeil von
* P1 (x1, y1) nach P2 (x2, y2) darstellt (in eine Richtung).
*
* @param xx1 X-Koordinate des Startpunkts des Pfeils.
* @param xx2 X-Koordinate des Endpunkts des Pfeils.
* @param yy1 Y-Koordinate des Startpunkts des Pfeils.
* @param yy2 Y-Koordinate des Endpunkts des Pfeils.
* @param staerke Die St�rke des Pfeils.
* @param gebogen Ob der Pfeil gebogen sein darf.
*
* @return Polygon in Gestalt eines Pfeils.
*/
public Polygon pfeilEinfach(final int xx1,
final int yy1,
final int xx2,
final int yy2,
final double staerke,
final boolean gebogen) {
return this.bezierPfeil(xx1, yy1, xx2, yy2, staerke, gebogen);
}
/**
* Gibt die Eckpunkte eines Polygons zur�ck, das einen Pfeil von
* P1 (x1, y1) nach P2 (x2, y2) darstellt (in eine Richtung).
*
* @param xx1 X-Koordinate des Startpunkts des Pfeils.
* @param yy1 Y-Koordinate des Startpunkts des Pfeils.
* @param xx2 X-Koordinate des Endpunkts des Pfeils.
* @param yy2 Y-Koordinate des Endpunkts des Pfeils.
* @param staerke Die St�rke des Pfeils.
* @param gebogen Ob der Pfeil gebogen sein soll.
*
* @return Polygon in Gestalt eines Pfeils.
*/
public Polygon bezierPfeil(
final int xx1,
final int yy1,
final int xx2,
final int yy2,
final double staerke,
final boolean gebogen) {
int x1 = xx1;
int y1 = yy1;
int x2 = xx2;
int y2 = yy2;
double letztX;
double letztY;
Polygon dieseKante;
int konstVersch = (int) ((double) Konstanten.PFEIL_DICKE * 2.3);
double vektorLen;
double x1d;
double x2d;
double y1d;
double y2d;
Polygon2D bez;
ArrayList<Double> dick;
Vektor2D pk0, pk1, pk2, pk3;
if (!gebogen) {
Vektor2D p1 = new Vektor2D(xx1, yy1);
Vektor2D p2 = new Vektor2D(xx2, yy2);
Polygon2D a = new Polygon2D(2);
a.add(p1);
a.add(p2);
dick = new ArrayList<Double>(2);
dick.add(staerke * Konstanten.DICKEN_REG_ST
+ this.pfeilDicke);
dick.add((double) this.pfeilDicke);
return this.segmentPfeilPol(a,
dick,
DOPPELSPITZES_ENDE,
EINFACHE_SPITZE_1,
new Vektor2D(1, 1),
new Vektor2D(1, 1),
1,
Vektor2D.NULL_VEKTOR);
}
if (x1 == x2 && y1 == y2) {
letztX = x1 + Konstanten.KN_DURCHM / 2;
letztY = y1 + Konstanten.KN_DURCHM / 2;
pk0 = new Vektor2D(letztX,
letztY);
pk1 = new Vektor2D(letztX + 80,
letztY + 40);
pk2 = new Vektor2D(letztX + 80,
y1 - Konstanten.KN_DURCHM / 2
+ this.pfeilDicke / 2 - 30);
pk3 = new Vektor2D(letztX + this.pfeilSpLaenge - 2,
y1 - Konstanten.KN_DURCHM / 2
+ this.pfeilDicke / 2 - 9);
bez = fmg.fmg8.graphVis.zeichenModi.Geometrie2D.bezierKurve(
pk0,
pk1,
pk2,
pk3,
this.pars.getBezier());
if (this.pars.getEinfacheDar()) {
dick = null;
} else {
dick = new ArrayList<Double>(bez.size());
for (double i = 0; i <= bez.size(); i++) {
dick.add((bez.size() - i) * staerke / bez.size()
* Konstanten.DICKEN_REG_ST
+ this.pfeilDicke);
}
}
return this.segmentPfeilPol(bez,
dick,
DOPPELSPITZES_ENDE,
EINFACHE_SPITZE_1,
new Vektor2D(1, 1),
new Vektor2D(1, 1),
1,
Vektor2D.NULL_VEKTOR);
} else {
Vektor2D vv = new Vektor2D(x2, y2);
vv.sub(new Vektor2D(x1, y1));
vv.normal();
vv.mult(35);
x1 += vv.x;
y1 += vv.y;
x2 -= vv.x;
y2 -= vv.y;
// Die aktuelle Kante ist eine Doppelkante.
if (this.aktGraph.enthaeltPfeil(xx2, yy2, xx1, yy1)) {
x1d = (double) x1;
x2d = (double) x2;
y1d = (double) y1;
y2d = (double) y2;
vektorLen = Math.sqrt(Math.pow(x2d - x1d, 2)
+ Math.pow(y1d - y2d, 2));
dieseKante = new Polygon();
dieseKante.addPoint(x1, y1);
dieseKante.addPoint(x2, y2);
if (this.dopp.contains(dieseKante)) {
x1d = x1d + ((y1d - y2d) / vektorLen) * konstVersch;
x2d = x2d + ((y1d - y2d) / vektorLen) * konstVersch;
y1d = y1d + ((x2d - x1d) / vektorLen) * konstVersch;
y2d = y2d + ((x2d - x1d) / vektorLen) * konstVersch;
} else {
x1d = x1d - ((y1d - y2d) / vektorLen) * konstVersch;
x2d = x2d - ((y1d - y2d) / vektorLen) * konstVersch;
y1d = y1d - ((x2d - x1d) / vektorLen) * konstVersch;
y2d = y2d - ((x2d - x1d) / vektorLen) * konstVersch;
this.dopp.add(dieseKante);
}
x1 = (int) x1d;
x2 = (int) x2d;
y1 = (int) y1d;
y2 = (int) y2d;
} else {
Vektor2D v0 = new Vektor2D(x2, y2);
v0.sub(new Vektor2D(x1, y1));
v0.ortho();
v0.normal();
v0.mult(12);
x1 += v0.x;
x2 += v0.x;
y1 += v0.y;
y2 += v0.y;
}
Polygon pol1 = new Polygon();
Polygon pol2 = new Polygon();
pol1.addPoint(xx1, yy1);
pol1.addPoint(xx2, yy2);
pol2.addPoint(x1, y1);
pol2.addPoint(x2, y2);
this.urspKanten.add(pol1);
this.echteKant.add(pol2);
Vektor2D v = new Vektor2D(x2, y2);
double dist = new Vektor2D(x1, y1).distanz(new Vektor2D(x2, y2));
v.sub(new Vektor2D(x1, y1));
v.normal();
v.mult(this.pfeilSpLaenge);
Vektor2D v1 = new Vektor2D(x1, y1);
Vektor2D v2 = new Vektor2D(x2, y2);
v2.sub(v);
Vektor2D n1 = new Vektor2D((x1 + x2) / 2, (y1 + y2) / 2);
Vektor2D n2 = new Vektor2D((x1 + x2) / 2, (y1 + y2) / 2);
v.ortho();
v.normal();
Vektor2D zwisch = new Vektor2D(x2, y2);
zwisch.sub(new Vektor2D(x1, y2));
v.mult(Math.sqrt(Math.max(dist - 100, 0)) + 0.1);
n1.add(v);
n2.add(v);
bez = fmg.fmg8.graphVis.zeichenModi.Geometrie2D.bezierKurve(
v1,
n1,
n2,
v2,
this.pars.getBezier());
if (this.pars.getEinfacheDar()) {
dick = null;
} else {
dick = new ArrayList<Double>(bez.size());
for (double i = 0; i <= bez.size(); i++) {
dick.add((bez.size() - i) * staerke / bez.size()
* Konstanten.DICKEN_REG_ST
+ this.pfeilDicke);
}
}
return this.segmentPfeilPol(bez,
dick,
DOPPELSPITZES_ENDE,
EINFACHE_SPITZE_1,
new Vektor2D(1, 1),
new Vektor2D(1, 1),
1,
Vektor2D.NULL_VEKTOR);
}
}
/**
* Gibt einen einfachen Knoten als quadratisches Polygon zur�ck.
*
* @param x X-Koordinate des Knotens.
* @param y Y-Koordinate des Knotens.
*
* @return Polygon, das den Knoten repr�sentiert.
*/
public Polygon knotenEinfach(final int x, final int y) {
final Polygon quadrat = new Polygon();
double xQ;
double yQ;
xQ = x - this.knotenDurchm / 2.0;
yQ = y - this.knotenDurchm / 2.0;
quadrat.addPoint((int) xQ, (int) yQ);
xQ = x - this.knotenDurchm / 2.0;
yQ = y + this.knotenDurchm / 2.0;
quadrat.addPoint((int) xQ, (int) yQ);
xQ = x + this.knotenDurchm / 2.0;
yQ = y + this.knotenDurchm / 2.0;
quadrat.addPoint((int) xQ, (int) yQ);
xQ = x + this.knotenDurchm / 2.0;
yQ = y - this.knotenDurchm / 2.0;
quadrat.addPoint((int) xQ, (int) yQ);
return fmg.fmg8.graphVis.zeichenModi.Geometrie2D.kreis(
new Vektor2D(x, y),
31,
(int) (1 / this.pars.getBezier()));
}
/**
* Gibt einen Graphen als Liste von Polygon-Objekten zur�ck,
* die mit Java.Awt direkt gezeichnet werden k�nnen. Beschriftungen werden
* nicht gezeichnet.
*
* @param g Zu zeichnender Graph.
*
* @return Liste von zu zeichnenden Objekten.
*/
public List<Object> graph(final DargestellterGraph g) {
final ArrayList<Object> polygonListe = new ArrayList<Object>();
final ArrayList<Point> knotenKoord = g.holeKnotenKoord();
final ArrayList<Double> pfeilStaerken = g.holePfeilStaerken();
final ArrayList<Knoten> knotenObj = g.holeKnotenObj();
final ArrayList<Point> pfeilUrsp = g.holePfeilUrspr();
final ArrayList<Point> pfeilEnpk = g.holePfeilEnd();
final ArrayList<String> beschr = g.holeBeschr();
final ArrayList<Point> beschrKoord = g.holeBeschrKoord();
final ArrayList<Boolean> pfeilGebogen = g.holePfeilBiegung();
Polygon aktuellesPol;
String aktBeschr;
Point aktPunktU;
Point aktPunktE;
Point aktPunktK;
Point aktPunktB;
final Iterator<Point> itU;
final Iterator<Point> itE;
final Iterator<Double> itS;
final Iterator<Point> itK;
final Iterator<Knoten> itKO2;
final Iterator<Boolean> itG;
final Iterator<String> itB;
final Iterator<Point> itBK;
final AusgMerkm ausgPfeile;
AusgMerkm ausgKnoten;
Color knotenFarbe;
Object aktKnot;
this.aktGraph = g;
if (this.pars.getEinfacheDar()) {
ausgPfeile = new AusgMerkm(Color.BLACK,
Color.LIGHT_GRAY,
true,
true,
"Calibri",
Font.PLAIN,
14);
} else {
ausgPfeile = new AusgMerkm(Color.BLACK,
Color.ORANGE,
true,
true,
"Calibri",
Font.PLAIN,
14);
}
itU = pfeilUrsp.iterator();
itE = pfeilEnpk.iterator();
itS = pfeilStaerken.iterator();
itG = pfeilGebogen.iterator();
polygonListe.add(ausgPfeile);
while (itU.hasNext() && itE.hasNext() && itS.hasNext()) {
aktPunktU = itU.next();
aktPunktE = itE.next();
aktuellesPol = this.pfeilEinfach(aktPunktU.x,
aktPunktU.y,
aktPunktE.x,
aktPunktE.y,
itS.next(),
itG.next());
polygonListe.add(aktuellesPol);
}
itK = knotenKoord.iterator();
itKO2 = knotenObj.iterator();
while (itK.hasNext() && itKO2.hasNext()) {
aktKnot = itKO2.next();
aktPunktK = itK.next();
if (g.getSelektiert(aktKnot)) {
if (this.pars.getEinfacheDar()) {
knotenFarbe = Color.LIGHT_GRAY;
} else {
knotenFarbe = Konstanten.MARKIERT_FUELL_FARBE;
}
} else {
if (this.pars.getEinfacheDar()) {
knotenFarbe = Color.white;
} else {
knotenFarbe = Konstanten.STANDARD_FUELL_FARBE;
}
}
ausgKnoten = new AusgMerkm(Color.BLACK,
knotenFarbe,
true,
true,
"Calibri",
Font.PLAIN,
14);
aktuellesPol = this.knotenEinfach(aktPunktK.x, aktPunktK.y);
polygonListe.add(ausgKnoten);
polygonListe.add(aktuellesPol);
}
itB = beschr.iterator();
itBK = beschrKoord.iterator();
while (itB.hasNext() && itBK.hasNext()) {
int x;
int y;
Polygon pol;
Polygon ass;
int x1;
int x2;
int y1;
int y2;
int x1ass;
int x2ass;
int y1ass;
int y2ass;
aktPunktB = itBK.next();
aktBeschr = itB.next();
String nBeschr;
int nBInt;
x = aktPunktB.x;
y = aktPunktB.y;
ass = (Polygon) g.holeAssoz(aktBeschr);
if (ass != null && ass.npoints == 0) {
int trennInd = 0;
while (aktBeschr.charAt(trennInd) != '-') {
trennInd++;
}
nBInt = Integer.parseInt(aktBeschr.substring(0, trennInd));
nBeschr = aktBeschr.substring(trennInd);
aktBeschr = fmg.fmg8.umgebung2D.Konstanten.BEF[nBInt] + nBeschr;
ass = null;
}
if (ass != null) {
int i = 0;
x1ass = ass.xpoints[0];
x2ass = ass.xpoints[1];
y1ass = ass.ypoints[0];
y2ass = ass.ypoints[1];
while (i < this.urspKanten.size()) {
pol = (Polygon) this.urspKanten.get(i);
x1 = pol.xpoints[0];
x2 = pol.xpoints[1];
y1 = pol.ypoints[0];
y2 = pol.ypoints[1];
if (x1ass == x1 && x2ass == x2
&& y1ass == y1 && y2ass == y2) {
if (x1 != x2 || y1 != y2) {
pol = (Polygon) this.echteKant.get(i);
x1 = pol.xpoints[0];
x2 = pol.xpoints[1];
y1 = pol.ypoints[0];
y2 = pol.ypoints[1];
Vektor2D verschOrtho = new Vektor2D(x1, y1);
verschOrtho.sub(new Vektor2D(x2, y2));
Vektor2D verschPar = new Vektor2D(verschOrtho);
verschPar.normal();
verschPar.mult(30);
verschOrtho.ortho();
verschOrtho.normal();
verschOrtho.mult(-10);
Vektor2D versch = new Vektor2D(verschPar);
versch.add(verschOrtho);
x = (int) (((double) x1 + (double) x2) / 2.0
+ versch.x);
y = (int) (((double) y1 + (double) y2) / 2.0
+ versch.y);
}
}
i++;
}
}
polygonListe.add(new Integer(x));
polygonListe.add(new Integer(y));
polygonListe.add(aktBeschr);
}
this.aktGraph = null;
this.dopp.clear();
this.urspKanten.clear();
this.echteKant.clear();
return polygonListe;
}
/**
* Gibt einen Pfeil als Java-Polygon zur�ck, der in mehreren Segmenten
* durch die �bergebenen Punkte verl�uft. Diese Methode basiert auf
* <code>segmentPfeilPol2D</code>
*
* @param punkte Die Punkte, durch die der Pfeil verlaufen soll.
* @param dicken Die Dicken des Pfeils an den Stellen der
* Verlaufspunkte.
* @param pfeilAnfang Die Spitze des Pfeils am Beginn.
* @param pfeilEnde Die Spitze des Pfeils am Ende.
* @param anfFaktor Multiplikativer Faktor f�r die Gr��e der Enden.
* @param endFaktor Multiplikativer Faktor f�r die Gr��e der Enden.
* @param gesamtskalierung Skalierung des gesamten Polygons.
* @param versch Die Verschiebung.
*
* @return Der Pfeil aus mehreren Segmenten.
*/
public Polygon segmentPfeilPol(final Polygon2D punkte,
final ArrayList<Double> dicken,
final Polygon2D pfeilAnfang,
final Polygon2D pfeilEnde,
final Vektor2D anfFaktor,
final Vektor2D endFaktor,
final double gesamtskalierung,
final Vektor2D versch) {
Polygon2D pfeilArr = this.segmentPfeilPol2D(
punkte,
dicken,
pfeilAnfang,
pfeilEnde,
anfFaktor,
endFaktor);
return pfeilArr.toPol(gesamtskalierung, versch);
}
/**
* Gibt einen Pfeil zur�ck, der in mehreren Segmenten durch die
* �bergebenen Punkte verl�uft. Der Pfeil wird als Polygon2D
* (und nicht als Java-Polygon) zur�ckgegeben.
*
* @param punkte Die Punkte, durch die der Pfeil verlaufen soll.
* @param dicken Die Dicken des Pfeils an den Stellen der
* Verlaufspunkte.
* @param pfeilAnfang Die Spitze des Pfeils am Beginn.
* @param pfeilEnde Die Spitze des Pfeils am Ende.
* @param anfFaktor Multiplikativer Faktor f�r die Gr��e der Enden.
* @param endFaktor Multiplikativer Faktor f�r die Gr��e der Enden.
*
* @return Der Pfeil aus mehreren Segmenten.
*/
public Polygon2D segmentPfeilPol2D(
final Polygon2D punkte,
final ArrayList<Double> dicken,
final Polygon2D pfeilAnfang,
final Polygon2D pfeilEnde,
final Vektor2D anfFaktor,
final Vektor2D endFaktor) {
Vektor2D aktVekX;
Vektor2D aktVekY;
Vektor2D aktVek;
Strecke2D p, q;
if (punkte == null || punkte.size() < 2) {
throw new RuntimeException("Zu wenige Segmente f�r Pfeil.");
}
ArrayList<Double> dick = dicken;
if (dick == null) {
dick = new ArrayList<Double>(punkte.size());
for (int i = 0; i < punkte.size(); i++) {
dick.add((double) this.pfeilDicke);
}
}
Polygon2D pktList1 = new Polygon2D(punkte.size()
+ pfeilAnfang.size()
+ pfeilEnde.size());
Polygon2D pktList2 = new Polygon2D(pktList1.size());
// Pfeilanfang.
Vektor2D normAnf = new Vektor2D(punkte.get(0));
Vektor2D orthoAnf;
normAnf.sub(punkte.get(1));
normAnf.normal();
orthoAnf = new Vektor2D(normAnf);
orthoAnf.ortho();
Iterator<Vektor2D> it1 = pfeilAnfang.iterator();
Polygon2D zwisch = new Polygon2D(pfeilAnfang.size());
while (it1.hasNext()) {
aktVek = it1.next();
aktVekX = new Vektor2D(orthoAnf);
aktVekY = new Vektor2D(normAnf);
aktVekX.mult(aktVek.x * anfFaktor.x * dick.get(0));
aktVekY.mult(aktVek.y * anfFaktor.y * dick.get(0));
aktVek = new Vektor2D(aktVekX);
aktVek.add(aktVekY);
aktVek.add(punkte.get(0));
zwisch.add(aktVek);
}
for (int i = zwisch.size() - 1; i >= 0; i--) {
pktList2.add(zwisch.get(i));
}
Polygon2D zwischPunkte;
Vektor2D c1 = new Vektor2D(punkte.get(1));
Vektor2D c2;
c1.sub(punkte.get(0));
c1.ortho();
c1.normal();
c1.mult((double) dick.get(0) / 2);
Vektor2D p01 = new Vektor2D(punkte.get(0));
Vektor2D p02 = new Vektor2D(p01);
Vektor2D p11;
Vektor2D p12;
p01.add(c1);
p02.sub(c1);
pktList1.add(p01);
pktList2.add(p02);
for (int i = 1; i < punkte.size() - 1; i++) {
zwischPunkte = fmg.fmg8.graphVis.zeichenModi.Geometrie2D.schnPkte(
punkte.get(i - 1),
punkte.get(i),
punkte.get(i + 1),
dick.get(i));
p = new Strecke2D(
zwischPunkte.get(0),
zwischPunkte.get(1));
q = new Strecke2D(
pktList1.get(pktList1.size() - 1),
pktList2.get(pktList2.size() - 1));
if (p.schnPkt(q) == null) {
pktList1.add(zwischPunkte.get(0));
pktList2.add(zwischPunkte.get(1));
} else {
SonstMeth.log(SonstMeth.LOG_WARNING,
"Segment konnte nicht �berschneidungsfrei "
+ "platziert werden um Pixel: " + punkte.get(i),
this.pars,
"",
punkte.get(i));
pktList1.add(zwischPunkte.get(0));
pktList2.add(zwischPunkte.get(1));
}
}
c2 = new Vektor2D(punkte.get(punkte.size() - 1));
c2.sub(punkte.get(punkte.size() - 2));
c2.ortho();
c2.normal();
c2.mult((double) dick.get(punkte.size() - 1) / 2);
p11 = new Vektor2D(punkte.get(punkte.size() - 1));
p12 = new Vektor2D(p11);
p11.add(c2);
p12.sub(c2);
pktList1.add(p11);
pktList2.add(p12);
// Pfeilspitze.
Vektor2D normEnd = new Vektor2D(punkte.get(punkte.size() - 1));
Vektor2D orthoEnd;
normEnd.sub(punkte.get(punkte.size() - 2));
normEnd.normal();
orthoEnd = new Vektor2D(normEnd);
orthoEnd.ortho();
Iterator<Vektor2D> it2 = pfeilEnde.iterator();
while (it2.hasNext()) {
aktVek = it2.next();
aktVekX = new Vektor2D(orthoEnd);
aktVekY = new Vektor2D(normEnd);
aktVekX.mult(aktVek.x * endFaktor.x * dick.get(dick.size() - 1));
aktVekY.mult(aktVek.y * endFaktor.y * dick.get(dick.size() - 1));
aktVek = new Vektor2D(aktVekX);
aktVek.add(aktVekY);
aktVek.add(punkte.get(punkte.size() - 1));
pktList1.add(aktVek);
}
for (int i = pktList2.size() - 1; i >= 0; i--) {
pktList1.add(pktList2.get(i));
}
return pktList1;
}
/**
* Vereinfachter Pfeilerzeuger.
*
* @param punkte Die Punkte, durch die der Pfeil laufen soll.
* @return Das Polygon.
*/
public Polygon2D segmentPfeilPol2D(final Polygon2D punkte) {
return this.segmentPfeilPol2D(
punkte,
null,
PfeilMaster.EINFACHER_ABSCHLUSS,
PfeilMaster.EINFACHE_SPITZE_2,
new Vektor2D(1, 1),
new Vektor2D(1, 1));
}
/**
* Markiert die Ecken des Polygons durch Kreise in der Liste der zu
* zeichnenden Objekte.
*
* @param p Das Polygon.
* @param l Die Liste der Objekte.
* @param markierung Welche Ecken markiert werden sollen.
* @param mark Die Ausgabemerkmale f�r die markierten Knoten.
* @param unmark Die Ausgabemerkmale f�r die unmarkierten Knoten.
* @param radius Der Radius der Kreise.
*/
public void markiereEcken(
final Polygon p,
final List<Object> l,
final List<Integer> markierung,
final AusgMerkm mark,
final AusgMerkm unmark,
final double radius) {
Vektor2D v;
Kreis2D k;
for (int i = 0; i < p.npoints; i++) {
if (markierung.contains(i)) {
l.add(mark);
} else {
l.add(unmark);
}
v = new Vektor2D(p.xpoints[i], p.ypoints[i]);
k = new Kreis2D(v.x, v.y, radius);
l.add(k);
}
}
/**
* Erzeugt einen gestrichelten Pfeil mit zwei verschiedenen Segmenttypen.
*
* @param punkte Die Punkte des Pfeils.
* @param dicken Die Dicken des Pfeils.
* @param pfeilAnfang Das Pfeilanfangspolygon.
* @param pfeilEnde Das Pfeilendepolygon.
* @param anfFaktor Der Anfangsfaktor.
* @param endFaktor Der Endfaktor.
* @param farben Eine beliebige Liste sich abwechselnder
* Ausgabemerkmale. Ist hier ein Eintrag
* <code>null</code>, wird kein Ausgabemerkmal
* f�r die Segmente definiert.
* @param strichLenFaktor Multiplikativer Faktor f�r die L�nge eines
* Segments bezogen auf die durchschnittliche
* Dicke des Pfeils.
* @param params Die Parameter.
* @return Der gestrichelte Pfeil als Menge von Segmentpolygonen.
*/
public Pol2DMitAusgMerkm[] gestrichelterPfeil(
final Polygon2D punkte,
final ArrayList<Double> dicken,
final Polygon2D pfeilAnfang,
final Polygon2D pfeilEnde,
final Vektor2D anfFaktor,
final Vektor2D endFaktor,
final AusgMerkm[] farben,
final double strichLenFaktor,
final Parametersatz params) {
SegSpez[] segBeschr;
final double konstFakt = 3 * strichLenFaktor;
double strLaeng;
double durchDick = 0;
double durchAbst = 0;
double anzPunkte;
int j;
AusgMerkm farbe;
Polygon2D anfang;
Polygon2D ende;
double mehrPunkte;
double anzSegmente;
if (dicken != null) {
for (int i = 0; i < dicken.size(); i++) {
durchDick += Math.abs(dicken.get(i));
}
durchDick /= dicken.size();
} else {
durchDick = Konstanten.PFEIL_DICKE;
}
for (int i = 0; i < punkte.size() - 2; i++) {
durchAbst += punkte.get(i).distanz(punkte.get(i + 1));
}
durchAbst /= punkte.size() - 1;
strLaeng = durchDick * konstFakt;
anzPunkte = strLaeng / durchAbst;
if (anzPunkte == 0) {
return this.gestrichelterPfeil(
punkte,
dicken,
pfeilAnfang,
pfeilEnde,
anfFaktor,
endFaktor,
farben,
strichLenFaktor + 1,
params);
}
segBeschr = new SegSpez[(int) (punkte.size() / anzPunkte + 1)];
anzSegmente = punkte.size() / anzPunkte;
mehrPunkte = punkte.size() % anzPunkte;
anzPunkte += mehrPunkte / ((int) anzSegmente + 1);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Segmente werden hinzugef�gt:",
this.pars);
j = 0;
for (double i = 0; i <= punkte.size() - anzPunkte; i += anzPunkte) {
farbe = farben[(int) j % farben.length];
anfang = PfeilMaster.EINFACHER_ABSCHLUSS;
ende = PfeilMaster.EINFACHER_ABSCHLUSS;
if (i == 0) {
anfang = pfeilAnfang;
SonstMeth.log(
SonstMeth.LOG_DEBUG,
" " + anzPunkte,
this.pars,
"plain",
null);
}
if (i + anzPunkte > punkte.size() - anzPunkte) {
ende = pfeilEnde;
anzPunkte = punkte.size() - i - 1;
SonstMeth.log(
SonstMeth.LOG_DEBUG,
" * " + j + " + " + anzPunkte + ".",
this.pars,
"plain",
null);
}
segBeschr[j] = new SegSpez(
farbe,
(int) i,
(int) (i + anzPunkte),
anfang,
ende,
anfFaktor,
endFaktor);
j++;
}
return this.erzeugePfeilsegmente(punkte, dicken, segBeschr, params);
}
/**
* Gibt eine beliebige Menge von beliebig zusammenh�ngenden Teilsegmenten
* eines Pfeils zur�ck, wobei die Ausgabemerkmale f�r jedes zus.
* Teilsegment einzeln eingestellt werden k�nnen.
*
* @param punkte Die Punkte, durch die der Pfeil verlaufen soll.
* @param dicken Die Dicken des Pfeils an den Stellen der
* Verlaufspunkte.
* @param segBeschr Die Beschreibungen einzelner Segmente.
* @param params Die Parameter.
*
* @return Die Teilsegmente eines Pfeil aus mehreren Segmenten.
*/
public Pol2DMitAusgMerkm[] erzeugePfeilsegmente(
final Polygon2D punkte,
final ArrayList<Double> dicken,
final SegSpez[] segBeschr,
final Parametersatz params) {
Pol2DMitAusgMerkm[] segmente = new Pol2DMitAusgMerkm[segBeschr.length];
Polygon2D aktPol;
Polygon2D aktPunkte = new Polygon2D();
ArrayList<Double> aktDicken = new ArrayList<Double>();
PfeilMaster zeichnen = new PfeilMaster(params);
AusgMerkm ausg;
GradientPaint grad;
Vektor2D p1Old, p2Old, p1, p2, v1, v2, zwisch;
Color fuell, rahmen;
for (int i = 0; i < segBeschr.length; i++) {
if (segBeschr[i] != null) {
aktPunkte.clear();
aktDicken.clear();
for (int j = segBeschr[i].getBeginn();
j <= segBeschr[i].getEnde(); j++) {
aktPunkte.add(punkte.get(j));
if (dicken != null) {
aktDicken.add(dicken.get(j));
} else {
aktDicken.add((double) Konstanten.PFEIL_DICKE);
}
}
aktPol = zeichnen.segmentPfeilPol2D(
aktPunkte,
aktDicken,
segBeschr[i].getPfeilAnfang(),
segBeschr[i].getPfeilEnde(),
segBeschr[i].getFaktorAnfang(),
segBeschr[i].getFaktorEnde());
ausg = segBeschr[i].getAusg();
if (ausg != null && ausg.getGradPaint() != null) {
p1Old = new Vektor2D(
ausg.getGradPaint().getPoint1().getX(),
ausg.getGradPaint().getPoint1().getY());
p2Old = new Vektor2D(
ausg.getGradPaint().getPoint2().getX(),
ausg.getGradPaint().getPoint2().getY());
v1 = new Vektor2D(aktPunkte.get(aktPunkte.size() - 1));
v1.sub(aktPunkte.get(0));
v2 = new Vektor2D(v1);
v2.ortho();
p1 = new Vektor2D(v1);
p1.mult(p1Old.y);
zwisch = new Vektor2D(v2);
zwisch.mult(p1Old.x);
p1.add(zwisch);
p1.add(aktPunkte.get(0));
p2 = new Vektor2D(v1);
p2.mult(p2Old.y);
zwisch = new Vektor2D(v2);
zwisch.mult(p2Old.x);
p2.add(zwisch);
p2.add(aktPunkte.get(0));
grad = new GradientPaint(
(float) p1.x,
(float) p1.y,
ausg.getGradPaint().getColor1(),
(float) p2.x,
(float) p2.y,
ausg.getGradPaint().getColor2());
fuell = ausg.getFuellFarbe();
rahmen = ausg.getRahmenFarbe();
ausg = new AusgMerkm(
grad,
ausg.holeRahmenDrucken(),
ausg.holeFuellungDrucken());
ausg.setFuellFarbe(fuell);
ausg.setRahmenFarbe(rahmen);
}
segmente[i] = new Pol2DMitAusgMerkm(
aktPol,
ausg);
}
}
return segmente;
}
/**
* Main-Methode.
*
* @param args Argumente.
*/
public static void main(final String[] args) {
Parametersatz params = new Parametersatz(args);
params.ergaenze();
PfeilMaster zeichnen = new PfeilMaster(params);
AusgMerkm a1 = new AusgMerkm(Color.yellow, Color.black, true, true);
AusgMerkm a2 = new AusgMerkm(Color.yellow, Color.black, true, true);
List<Object> l;
Polygon2D bez2 = new Polygon2D();
ArrayList<Double> dicken = new ArrayList<Double>();
for (double i = 0; i < Math.PI * 2; i += 0.0001) {
bez2.add(new Vektor2D(Math.sin(i) * 10, Math.cos(i) * 10));
}
bez2 = bez2.normalisiere();
for (double i = 0; i < bez2.size(); i++) {
dicken.add(
Math.sin((i / bez2.size() * Math.PI * 4) * 4
+ Math.sin(i / bez2.size() * Math.PI * 6) * 1
+ Math.sin(i / bez2.size() * Math.PI * 8) * 2) * 3 + 4.5);
}
a1.setGradPaint(-3f, 0, Color.green, 3f, 0, Color.red);
a2.setGradPaint(-3f, 0, Color.darkGray, 3f, 0, Color.blue);
AusgMerkm[] ausg = new AusgMerkm[2];
ausg[0] = a1;
ausg[1] = a2;
Pol2DMitAusgMerkm[] seg = zeichnen.gestrichelterPfeil(
bez2,
dicken,
PfeilMaster.RUECK_PFEIL,
PfeilMaster.RUECK_PFEIL,
new Vektor2D(1, 1),
new Vektor2D(1, 1),
ausg,
0.1,
params);
Polygon2D pol = new Polygon2D();
pol.add(new Vektor2D(0, 15));
l = Geometrie2D.erzeugeObjList(seg, 100, Vektor2D.NULL_VEKTOR);
l.add(0, new AusgMerkm(Color.blue, Color.black, true, true));
l.add(pol.toPol(100, Vektor2D.NULL_VEKTOR));
Geometrie2D.saveObjectsToFile(l, "luke", "png", params);
}
}