Basisklassen

This commit is contained in:
ngb
2021-12-23 09:21:11 +01:00
parent 1a929e49a5
commit d82ee1410a
9 changed files with 1499 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
package schule.ngb.zm;
/**
* Aktualisierbare Objekte können in regelmäßigen Intervallen (meist einmal
* pro Frame) ihren Zustand aktualisieren. Diese Änderung kann abhängig vom
* Zeitintervall (in Sekunden) zum letzten Aufruf passieren.
*/
public interface Aktualisierbar {
/**
* Gibt an, ob das Objekt gerade auf Aktualisierungen reagiert.
* @return <code>true</code>, wenn das Objekt aktiv ist.
*/
public boolean istAktiv();
/**
* Änderung des Zustandes des Objekts abhängig vom Zeitintervall
* <var>delta</var> in Sekunden.
* @param delta Zeitintervall seit dem letzten Aufruf (in Sekunden).
*/
public void aktualisieren( double delta );
}

View File

@@ -0,0 +1,106 @@
package schule.ngb.zm;
import java.awt.*;
import java.awt.image.BufferedImage;
public abstract class Ebene extends Konstanten implements Zeichenbar, Aktualisierbar {
protected BufferedImage puffer;
protected Graphics2D zeichnung;
protected boolean sichtbar = true;
protected boolean aktiv = true;
public Ebene() {
this(STD_BREITE, STD_HOEHE);
}
public Ebene( int pBreite, int pHoehe ) {
zeichnungErstellen(pBreite, pHoehe);
}
public int getBreite() {
return puffer.getWidth();
}
public int getHoehe() {
return puffer.getHeight();
}
public void setGroesse( int pBreite, int pHoehe ) {
if( puffer != null ) {
zeichnenWiederherstellen(pBreite, pHoehe);
} else {
zeichnungErstellen(pBreite, pHoehe);
}
}
private void zeichnungErstellen( int pBreite, int pHoehe ) {
puffer = new BufferedImage(pBreite, pHoehe, BufferedImage.TYPE_INT_ARGB);
zeichnung = puffer.createGraphics();
// add antialiasing
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
hints.put(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY
);
zeichnung.addRenderingHints(hints);
}
private void zeichnenWiederherstellen( int pBreite, int pHoehe ) {
BufferedImage oldCanvas = puffer;
zeichnungErstellen(pBreite, pHoehe);
zeichnung.drawImage(oldCanvas, 0, 0, null);
}
/**
* Leert die Ebene und löscht alles bisher gezeichnete.
*/
public abstract void leeren();
/**
* Zeichnet den Puffer auf die Grafik-Instanz.
*
* @param pGraphics
*/
@Override
public void zeichnen( Graphics2D pGraphics ) {
if( sichtbar ) {
pGraphics.drawImage(puffer, 0, 0, null);
}
}
@Override
public boolean istSichtbar() {
return sichtbar;
}
public void verstecken() {
sichtbar = false;
}
public void zeigen() {
sichtbar = true;
}
public void umschalten() {
sichtbar = !sichtbar;
}
@Override
public void aktualisieren( double delta ) {
}
@Override
public boolean istAktiv() {
return aktiv;
}
}

View File

@@ -0,0 +1,95 @@
package schule.ngb.zm;
import java.awt.*;
public class Farbe extends Color {
public static final Farbe SCHWARZ = new Farbe(Color.BLACK);
public static final Farbe WEISS = new Farbe(Color.WHITE);
public static final Farbe GRAU = new Farbe(Color.GRAY);
public static final Farbe DUNKELGRAU = new Farbe(Color.DARK_GRAY);
public static final Farbe HELLGRAU = new Farbe(Color.LIGHT_GRAY);
public static final Farbe ROT = new Farbe(Color.RED);
public static final Farbe GRUEN = new Farbe(Color.GREEN);
public static final Farbe BLAU = new Farbe(Color.BLUE);
public static final Farbe GELB = new Farbe(Color.YELLOW);
public static final Farbe ORANGE = new Farbe(Color.ORANGE);
public static final Farbe CYAN = new Farbe(Color.CYAN);
public static final Farbe MAGENTA = new Farbe(Color.MAGENTA);
public static final Farbe PINK = new Farbe(Color.PINK);
public static final Farbe HGGRUEN = new Farbe(0, 165, 81);
public static final Farbe HGROT = new Farbe(151, 54, 60);
public Farbe( int pGrau ) {
super(pGrau, pGrau, pGrau, 255);
}
public Farbe( int pGrau, int pAlpha ) {
super(pGrau, pGrau, pGrau, pAlpha);
}
public Farbe( int pRot, int pGruen, int pBlau ) {
super(pRot, pGruen, pBlau);
}
public Farbe( int pRot, int pGruen, int pBlau, int pAlpha ) {
super(pRot, pGruen, pBlau, pAlpha);
}
public Farbe( Color pColor ) {
super(pColor.getRed(), pColor.getGreen(), pColor.getBlue(), pColor.getAlpha());
}
public Farbe( Color pColor, int pAlpha ) {
super(pColor.getRed(), pColor.getGreen(), pColor.getBlue(), pAlpha);
}
public static Farbe vonRGB( int pRGB ) {
return new Farbe(
(pRGB >> 16) & 255,
(pRGB >> 8) & 255,
pRGB & 255,
(pRGB >> 24) & 255);
}
public static Farbe vonHexcode( String pHexcode ) {
if( pHexcode.startsWith("#") ) {
pHexcode = pHexcode.substring(1);
}
int red = Integer.valueOf(pHexcode.substring(0, 2), 16);
int green = Integer.valueOf(pHexcode.substring(2, 4), 16);
int blue = Integer.valueOf(pHexcode.substring(4, 6), 16);
int alpha = 255;
if( pHexcode.length() == 8 ) {
alpha = Integer.valueOf(pHexcode.substring(6, 8), 16);
}
return new Farbe(red, green, blue, alpha);
}
public static Farbe morphen( Color pFarbe1, Color pFarbe2, double pFactor ) {
if( pFactor < 0.0 || pFarbe2 == null ) {
return new Farbe(pFarbe1);
}
if( pFactor > 1.0 || pFarbe1 == null )
return new Farbe(pFarbe2);
double pFactorInv = 1 - pFactor;
return new Farbe(
(int) (pFactorInv * pFarbe1.getRed() + pFactor * pFarbe2.getRed()),
(int) (pFactorInv * pFarbe1.getGreen() + pFactor * pFarbe2.getGreen()),
(int) (pFactorInv * pFarbe1.getBlue() + pFactor * pFarbe2.getBlue()),
(int) (pFactorInv * pFarbe1.getAlpha() + pFactor * pFarbe2.getAlpha())
);
}
public Farbe kopie() {
return new Farbe(this);
}
}

View File

@@ -0,0 +1,145 @@
package schule.ngb.zm;
import schule.ngb.zm.formen.Konturform;
import java.awt.*;
import java.awt.geom.Arc2D;
public class Konstanten {
public static final String APP_NAME = "Zeichenmaschine";
public static final int STD_BREITE = 400;
public static final int STD_HOEHE = 400;
public static final int STD_FPS = 60;
public static Color STD_HINTERGRUND = new Color(200, 200, 200);
public static final int DURCHGEZOGEN = Konturform.DURCHGEZOGEN;
public static final int GESTRICHELT = Konturform.GESTRICHELT;
public static final int GEPUNKTET = Konturform.GEPUNKTET;
public static final int OFFEN = Arc2D.OPEN;
public static final int GESCHLOSSEN = Arc2D.CHORD;
public static final int KREISTEIL = Arc2D.PIE;
public static final byte ZENTRUM = 0;
public static final byte NORDEN = 1 << 0;
public static final byte OSTEN = 1 << 2;
public static final byte SUEDEN = 1 << 3;
public static final byte WESTEN = 1 << 4;
public static final byte NORDOSTEN = NORDEN | OSTEN;
public static final byte SUEDOSTEN = SUEDEN | OSTEN;
public static final byte NORDWESTEN = NORDEN | WESTEN;
public static final byte SUEDWESTEN = SUEDEN | WESTEN;
public static final byte MITTE = ZENTRUM;
public static final byte OBEN = NORDEN;
public static final byte RECHTS = OSTEN;
public static final byte UNTEN = SUEDEN;
public static final byte LINKS = WESTEN;
public static final Farbe SCHWARZ = Farbe.SCHWARZ;
public static final Farbe WEISS = Farbe.WEISS;
public static final Farbe ROT = Farbe.ROT;
public static final Farbe BLAU = Farbe.BLAU;
public static final Farbe GRUEN = Farbe.GRUEN;
public static final Farbe GELB = Farbe.GELB;
public Farbe farbe( int pGrau ) {
return farbe(pGrau, pGrau, pGrau, 255);
}
public Farbe farbe( int pGrau, int pAlpha ) {
return farbe(pGrau, pGrau, pGrau, pAlpha);
}
public Farbe farbe(int red, int green, int blue) {
return farbe(red, green, blue, 255);
}
public Farbe farbe(int red, int green, int blue, int alpha) {
if (red < 0 || red >= 256)
throw new IllegalArgumentException("red must be between 0 and 255");
if (green < 0 || green >= 256)
throw new IllegalArgumentException("green must be between 0 and 255");
if (blue < 0 || blue >= 256)
throw new IllegalArgumentException("blue must be between 0 and 255");
if (alpha < 0 || alpha >= 256)
throw new IllegalArgumentException("alpha must be between 0 and 255");
return new Farbe(red, green, blue, alpha);
}
public double abs( double x ) {
return Math.abs(x);
}
public double vorzeichen( double x ) {
return Math.signum(x);
}
public double runden( double x ) {
return Math.round(x);
}
public double abrunden( double x ) {
return Math.floor(x);
}
public double aufrunden( double x ) {
return Math.ceil(x);
}
public double sin( double x ) {
return Math.sin(x);
}
public double cos( double x ) {
return Math.cos(x);
}
public double tan( double x ) {
return Math.tan(x);
}
public double arcsin( double x ) {
return Math.asin(x);
}
public double arccos( double x ) {
return Math.acos(x);
}
public double arctan( double x ) {
return Math.atan(x);
}
public double beschraenken( double x, double max ) {
if( x > max ) {
return max;
}
return x;
}
public double beschraenken( double x, double min, double max ) {
if( x > max ) {
return max;
}
if( x < min ) {
return min;
}
return x;
}
public double morphen( double pVon, double pNach, double pFaktor ) {
return pVon - pFaktor*(pVon+pNach);
}
}

View File

@@ -0,0 +1,118 @@
package schule.ngb.zm;
import schule.ngb.zm.formen.Formenebene;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* Eine Leinwand ist die Hauptkomponente einer Zeichenmaschine. Sie besteht aus
* mehreren Ebenen, auf denen auf verschiedene Arten gezeichnet werden kann. Die
* Ebenen lassen sich beliebig übereinander anordenen, ausblenden oder wieder
* löschen.
*
* Jede Ebene besitzt eine Zeichenfläche, auf der ihre Zeichnung liegt. Diese
* zeichenflächen werden pro Frame einmal von "unten" nach "oben" auf diese
* Leinwand gezeichnet.
*/
public class Leinwand extends JComponent {
private LinkedList<Ebene> ebenen;
public Leinwand( int pBreite, int pHoehe ) {
Dimension dim = new Dimension(pBreite, pHoehe);
super.setSize(pBreite, pHoehe);
this.setPreferredSize(dim);
this.setMinimumSize(dim);
ebenen = new LinkedList<>();
ebenen.add(new Zeichenebene());
ebenen.add(new Formenebene());
setBackground(Konstanten.STD_HINTERGRUND);
}
@Override
public void setSize( int pBreite, int pHoehe ) {
Dimension dim = new Dimension(pBreite, pHoehe);
super.setSize(pBreite, pHoehe);
this.setPreferredSize(dim);
this.setMinimumSize(dim);
for( Ebene ebene : ebenen ) {
ebene.setGroesse(getWidth(), getHeight());
}
}
public void hinzu( Ebene pEbene ) {
if( pEbene != null ) {
pEbene.setGroesse(getWidth(), getHeight());
ebenen.add(pEbene);
}
}
public void hinzu( int pIndex, Ebene pEbene ) {
if( pEbene != null ) {
pEbene.setGroesse(getWidth(), getHeight());
ebenen.add(pIndex, pEbene);
}
}
public java.util.List<Ebene> getEbenen() {
return ebenen;
}
/**
* Holt die {@link Ebene} am Index <var>i</var> (beginnend bei <code>0</code>).
*
* @param i Index der Ebene (beginnend bei <code>0</code>).
* @return Die Ebene am Index <var>i</var> oder <code>null</code>.
* @throws IndexOutOfBoundsException Falls der Index nicht existiert.
*/
public Ebene getEbene( int i ) {
if( ebenen.size() > i ) {
return ebenen.get(i);
} else {
throw new IndexOutOfBoundsException("Keine Ebene mit dem Index " + i + " vorhanden (maximum: " + (ebenen.size() - 1) + ").");
}
}
/**
* Holt die erste Ebene des angegebenen Typs aus der Liste der Ebenen.
* Existiert keine solche Ebene, wird <code>null</code> zurückgegeben.
*
* @param pClazz Typ der Ebene.
* @param <L>
* @return Erste Ebene vom angegeben Typ.
*/
public <L extends Ebene> L getEbene( Class<L> pClazz ) {
for( Ebene ebene : ebenen ) {
if( ebene.getClass().equals(pClazz) ) {
return pClazz.cast(ebene);
}
}
return null;
}
public <L extends Ebene> java.util.List<L> getEbenen( Class<L> pClazz ) {
ArrayList<L> result = new ArrayList<>(ebenen.size());
for( Ebene ebene : ebenen ) {
if( ebene.getClass().equals(pClazz) ) {
result.add(pClazz.cast(ebene));
}
}
return result;
}
public void paintComponent( Graphics g ) {
Graphics2D g2d = (Graphics2D) g.create();
for( Ebene ebene : ebenen ) {
ebene.zeichnen(g2d);
}
g2d.dispose();
}
}

View File

@@ -0,0 +1,251 @@
package schule.ngb.zm;
import java.awt.geom.Point2D;
public class Vektor extends Point2D.Double {
public Vektor() {
x = 0.0;
y = 0.0;
}
public Vektor(double pX, double pY) {
x = pX;
y = pY;
}
public Vektor(Point2D.Double pPunkt) {
x = pPunkt.getX();
x = pPunkt.getY();
}
public Vektor(Vektor pVektor) {
x = pVektor.x;
y = pVektor.y;
}
public static Vektor zufall() {
return new Vektor(Math.random()*100, Math.random()*100);
}
public static Vektor zufall( double min, double max ) {
return new Vektor(Math.random()*(max-min)+min, Math.random()*(max-min)+min);
}
public Vektor kopie() {
return new Vektor(x, y);
}
public Vektor set(double pX, double pY) {
x = pX;
y = pY;
return this;
}
public Vektor set(Vektor pVektor) {
x = pVektor.x;
y = pVektor.y;
return this;
}
public Vektor set(Point2D.Double pPunkt) {
x = pPunkt.getX();
x = pPunkt.getY();
return this;
}
public void setX(double pX) {
x = pX;
}
public void setY(double pY) {
y = pY;
}
public Point2D.Double getPunkt() {
return new Point2D.Double(x, y);
}
public double laenge() {
return Math.sqrt(x * x + y * y);
}
public double laengeQuad() {
return x * x + y * y;
}
public Vektor setLaenge(double pLaenge) {
normalisieren();
return skalieren(pLaenge);
}
public static Vektor setLaenge(Vektor pVektor, double pLaenge) {
Vektor vec = pVektor.kopie();
vec.setLaenge(pLaenge);
return vec;
}
public Vektor normalisieren() {
double len = laenge();
if (len != 0 && len != 1) {
x /= len;
y /= len;
}
return this;
}
public static Vektor normalisieren(Vektor pVektor) {
Vektor vec = pVektor.kopie();
vec.normalisieren();
return vec;
}
public Vektor addieren(Vektor pVektor) {
x += pVektor.x;
y += pVektor.y;
return this;
}
public Vektor addieren(double pX, double pY) {
x += pX;
y += pY;
return this;
}
public static Vektor addieren(Vektor pVektor1, Vektor pVektor2) {
Vektor vec = pVektor1.kopie();
vec.addieren(pVektor2);
return vec;
}
public void subtrahieren(Vektor pVektor) {
x -= pVektor.x;
y -= pVektor.y;
}
public void subtrahieren(double pX, double pY) {
x -= pX;
y -= pY;
}
public static Vektor subtrahieren(Vektor pVektor1, Vektor pVektor2) {
Vektor vec = pVektor1.kopie();
vec.subtrahieren(pVektor2);
return vec;
}
public Vektor skalieren(double pSkalar) {
x *= pSkalar;
y *= pSkalar;
return this;
}
public static Vektor skalieren(Vektor pVektor, double pSkalar) {
Vektor vec = pVektor.kopie();
vec.skalieren(pSkalar);
return vec;
}
public Vektor dividieren(double pSkalar) {
x /= pSkalar;
y /= pSkalar;
return this;
}
public static Vektor dividieren(Vektor pVektor, double pSkalar) {
Vektor vec = pVektor.kopie();
vec.dividieren(pSkalar);
return vec;
}
public double abstand(Vektor pVektor) {
double dx = x - pVektor.x;
double dy = y - pVektor.y;
return Math.sqrt(dx * dx + dy * dy);
}
public static double abstand(Vektor pVektor1, Vektor pVektor2) {
return pVektor1.abstand(pVektor2);
}
public double dot(Vektor pVektor) {
return x * pVektor.x + y * pVektor.y;
}
public double dot(double pX, double pY) {
return x * pX + y * pY;
}
public static double dot(Vektor pVektor1, Vektor pVektor2) {
return pVektor1.dot(pVektor2);
}
// See: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
public double cross(Vektor pVektor) {
return x * pVektor.y - pVektor.x * y;
}
public static double cross(Vektor pVektor1, Vektor pVektor2) {
return pVektor1.cross(pVektor2);
}
public void limitieren(double pMax) {
if (laengeQuad() > pMax * pMax) {
normalisieren();
skalieren(pMax);
}
}
public void beschraenken(double pMin, double pMax) {
if (pMin > pMax) {
throw new IllegalArgumentException("HVector.constrain(): pMin muss kleiner sein als pMax.");
}
if (laengeQuad() < pMin * pMin) {
normalisieren();
skalieren(pMin);
}
if (laengeQuad() > pMax * pMax) {
normalisieren();
skalieren(pMax);
}
}
public double richtung() {
double angle = Math.atan2(y, x);
return angle;
}
public double winkel() {
return richtung();
}
public Vektor drehen(double pWinkel) {
double temp = x;
x = x * Math.cos(pWinkel) - y * Math.sin(pWinkel);
y = temp * Math.sin(pWinkel) + y * Math.cos(pWinkel);
return this;
}
public static Vektor drehen(Vektor pVektor, double pWinkel) {
Vektor vec = pVektor.kopie();
vec.drehen(pWinkel);
return vec;
}
public void linterp(Vektor pVektor, float t) {
x = x + (pVektor.x - x) * t;
y = y + (pVektor.y - y) * t;
}
public static Vektor linterp(Vektor pVektor1, Vektor pVektor2, float t) {
Vektor vec = pVektor1.kopie();
vec.linterp(pVektor2, t);
return vec;
}
@Override
public String toString() {
return "schule.ngb.zm.Vektor{x = " + x + ", y = " + y + "}";
}
}

View File

@@ -0,0 +1,31 @@
package schule.ngb.zm;
import java.awt.*;
/**
* Zeichenbare Objekte können auf eine Zeichenfläche gezeichnet werden.
* In der Regel werden sie einmal pro Frame gezeichnet.
*/
public interface Zeichenbar {
/**
* Gibt an, ob das Objekt derzeit sichtbar ist (also gezeichnet werden
* muss).
*
* @return <code>true</code>, wenn das Objekt sichtbar ist.
*/
public boolean istSichtbar();
/**
* Wird aufgerufen, um das Objekt auf die Zeichenfläche <var>graphics</var>
* zu zeichnen.
* <p>
* Das Objekt muss dafür Sorge tragen, dass der Zustand der Zeichenfläche
* (Transformationsmatrix, Farbe, ...) erhalten bleibt. Das Objekt sollte
* also etwaige Änderungen am Ende des Aufrufs wieder rückgängig machen.
*
* @param graphics Die Zeichenfläche.
*/
public void zeichnen( Graphics2D graphics );
}

View File

@@ -0,0 +1,417 @@
package schule.ngb.zm;
import java.awt.*;
import java.awt.geom.*;
import java.util.Stack;
public class Zeichenebene extends Ebene {
private int default_anchor = ZENTRUM;
protected Color strokeColor;
protected Color fillColor;
protected double strokeWeight;
protected int konturArt = DURCHGEZOGEN;
public Color getColor() {
return fillColor;
}
public void noFill() {
fillColor = null;
}
public void setColor(int gray) {
setColor(gray, gray, gray, 255);
}
public void setColor(int gray, int alpha) {
setColor(gray, gray, gray, alpha);
}
public void setColor(int red, int green, int blue) {
setColor(red, green, blue, 255);
}
public void setColor(int red, int green, int blue, int alpha ) {
if (red < 0 || red >= 256) throw new IllegalArgumentException("red must be between 0 and 255");
if (green < 0 || green >= 256) throw new IllegalArgumentException("green must be between 0 and 255");
if (blue < 0 || blue >= 256) throw new IllegalArgumentException("blue must be between 0 and 255");
if (alpha < 0 || alpha >= 256) throw new IllegalArgumentException("alpha must be between 0 and 255");
setColor(new Color(red, green, blue, alpha));
}
public void setColor(Color pColor) {
fillColor = pColor;
zeichnung.setColor(pColor);
}
public Color getStrokeColor() {
return strokeColor;
}
public void noStroke() {
strokeColor = null;
}
public void setStrokeColor(int gray) {
setStrokeColor(gray, gray, gray, 255);
}
public void setStrokeColor(int gray, int alpha) {
setStrokeColor(gray, gray, gray, alpha);
}
public void setStrokeColor(int red, int green, int blue) {
if (red < 0 || red >= 256) throw new IllegalArgumentException("red must be between 0 and 255");
if (green < 0 || green >= 256) throw new IllegalArgumentException("green must be between 0 and 255");
if (blue < 0 || blue >= 256) throw new IllegalArgumentException("blue must be between 0 and 255");
setStrokeColor(red, green, blue, 255);
}
public void setStrokeColor(int red, int green, int blue, int alpha ) {
if (red < 0 || red >= 256) throw new IllegalArgumentException("red must be between 0 and 255");
if (green < 0 || green >= 256) throw new IllegalArgumentException("green must be between 0 and 255");
if (blue < 0 || blue >= 256) throw new IllegalArgumentException("blue must be between 0 and 255");
if (alpha < 0 || alpha >= 256) throw new IllegalArgumentException("alpha must be between 0 and 255");
setStrokeColor(new Color(red, green, blue, alpha));
}
public void setStrokeColor(Color pColor) {
strokeColor = pColor;
zeichnung.setColor(pColor);
}
public void setStrokeWeight( double pWeight ) {
strokeWeight = pWeight;
zeichnung.setStroke(createStroke());
}
protected Stroke createStroke() {
switch(konturArt) {
case GEPUNKTET:
return new BasicStroke(
(float) strokeWeight,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
10.0f, new float[]{1.0f, 5.0f}, 0.0f);
case GESTRICHELT:
return new BasicStroke(
(float) strokeWeight,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
10.0f, new float[]{5.0f}, 0.0f);
default:
return new BasicStroke(
(float) strokeWeight,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
}
}
public int getKonturArt() {
return konturArt;
}
public void setKonturArt(int konturArt) {
this.konturArt = konturArt;
}
private Stack<AffineTransform> transformStack = new Stack<>();
public Zeichenebene() {
super();
transformStack.push(new AffineTransform());
strokeColor = Color.BLACK;
fillColor = Color.WHITE;
strokeWeight = 1.0;
}
public Zeichenebene( int pWidth, int pHeight) {
super(pWidth, pHeight);
}
public void setAnchor( int pAnchor ) {
default_anchor = pAnchor;
}
public void leeren() {
clear(200);
}
public void clear(int gray) {
clear(gray, gray, gray, 255);
}
public void clear(int gray, int alpha) {
clear(gray, gray, gray, alpha);
}
public void clear(int red, int green, int blue) {
clear(red, green, blue, 255);
}
public void clear(int red, int green, int blue, int alpha) {
clear(new Color(red, green, blue, alpha));
}
public void clear(Color pColor) {
/*graphics.setBackground(pColor);
graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());*/
Color currentColor = zeichnung.getColor();
pushMatrix();
resetMatrix();
zeichnung.setColor(pColor);
zeichnung.fillRect(0, 0, puffer.getWidth(), puffer.getHeight());
zeichnung.setColor(currentColor);
popMatrix();
}
public void line(double x1, double y1, double x2, double y2) {
Shape line = new Line2D.Double(x1, y1, x2, y2);
//line = transformToCanvas(line);
drawShape(line);
}
public void pixel(double x, double y) {
square(x, y, 1);
}
public void square(double x, double y, double w) {
rect(x, y, w, w);
}
public void square(double x, double y, double w, int anchor) {
rect(x, y, w, w, anchor);
}
public void rect(double x, double y, double w, double h) {
rect(x, y, w, h, default_anchor);
}
public void rect(double x, double y, double w, double h, int anchor) {
Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
Shape rect = new Rectangle2D.Double(
anchorPoint.getX(), anchorPoint.getY(), w, h
);
//rect = transformToCanvas(rect);
fillShape(rect);
drawShape(rect);
}
public void point(double x, double y) {
circle(x - 1, y - 1, 2);
}
public void circle(double x, double y, double d) {
ellipse(x, y, d, d, default_anchor);
}
public void circle(double x, double y, double d, int anchor) {
ellipse(x, y, d, d, anchor);
}
public void ellipse(double x, double y, double w, double h) {
ellipse(x, y, w, h, default_anchor);
}
public void ellipse(double x, double y, double w, double h, int anchor) {
Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
Shape ellipse = new Ellipse2D.Double(
anchorPoint.x, anchorPoint.y, w, h
);
//ellipse = transformToCanvas(ellipse);
fillShape(ellipse);
drawShape(ellipse);
}
public void arc( double x, double y, double d, double angle1, double angle2 ) {
while (angle2 < angle1) angle2 += 360.0;
Point2D.Double anchorPoint = getAnchorPoint(x, y, d, d, ZENTRUM);
Shape arc = new Arc2D.Double(
anchorPoint.x,
anchorPoint.y,
d, d,
angle1, angle2 - angle1,
Arc2D.OPEN
);
//arc = transformToCanvas(arc);
drawShape(arc);
}
public void pie( double x, double y, double d, double angle1, double angle2 ) {
while (angle2 < angle1) angle2 += 360.0;
Point2D.Double anchorPoint = getAnchorPoint(x, y, d, d, ZENTRUM);
Shape arc = new Arc2D.Double(
anchorPoint.x,
anchorPoint.y,
d, d,
angle1, angle2 - angle1,
Arc2D.PIE
);
//arc = transformToCanvas(arc);
fillShape(arc);
drawShape(arc);
}
private Point2D.Double transformToCanvas(double x, double y) {
return transformToCanvas(new Point2D.Double(x, y));
}
private Point2D.Double transformToCanvas( Point2D.Double pPoint ) {
AffineTransform matrix = getMatrix();
matrix.transform(pPoint, pPoint);
return pPoint;
}
private Shape transformToCanvas( Shape pShape ) {
AffineTransform matrix = getMatrix();
return matrix.createTransformedShape(pShape);
}
private Point2D.Double transformToUser(double x, double y) {
return transformToUser(new Point2D.Double(x, y));
}
private Point2D.Double transformToUser( Point2D.Double pPoint ) {
AffineTransform matrix = getMatrix();
try {
matrix.inverseTransform(pPoint, pPoint);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return pPoint;
}
private Shape transformToUser( Shape pShape ) {
AffineTransform matrix = getMatrix();
try {
matrix = matrix.createInverse();
pShape = matrix.createTransformedShape(pShape);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return pShape;
}
private AffineTransform getAnchorTransform( Shape pShape, int anchor ) {
AffineTransform at = new AffineTransform();
Rectangle2D bounds = pShape.getBounds2D();
switch(anchor) {
case ZENTRUM:
at.translate(
bounds.getWidth() / -2.0,
bounds.getHeight() / -2.0
);
break;
case WESTEN:
at.translate(
0, bounds.getHeight() / -2.0
);
break;
case SUEDWESTEN:
at.translate(
0, -1.0 * bounds.getHeight()
);
break;
}
return at;
}
private Point2D.Double getAnchorPoint(double x, double y, double w, double h, int anchor) {
switch(anchor) {
case ZENTRUM:
x -= w / 2.0;
y -= h / 2.0;
break;
case WESTEN:
y -= h / 2.0;
break;
case SUEDWESTEN:
y -= h;
break;
}
return new Point2D.Double(x, y);
}
private Point2D.Double getAnchorPoint(Shape pShape, int anchor) {
Rectangle2D bounds = pShape.getBounds2D();
return getAnchorPoint(
bounds.getX(), bounds.getY(),
bounds.getWidth(), bounds.getHeight(), anchor
);
}
private void fillShape( Shape pShape ) {
if (fillColor != null && fillColor.getAlpha() > 0.0) {
zeichnung.setColor(fillColor);
zeichnung.fill(pShape);
}
}
private void drawShape( Shape pShape ) {
if (strokeColor != null && strokeColor.getAlpha() > 0.0
&& strokeWeight > 0.0 ) {
zeichnung.setColor(strokeColor);
zeichnung.draw(pShape);
}
}
public void translate( double dx, double dy ) {
zeichnung.translate(dx, dy);
}
public void scale( double factor ) {
zeichnung.scale(factor, factor);
}
public void rotate( double pAngle ) {
zeichnung.rotate(Math.toRadians(pAngle));
}
public void shear( double dx, double dy ) {
zeichnung.shear(dx, dy);
}
public AffineTransform getMatrix() {
return zeichnung.getTransform();
}
public void pushMatrix() {
transformStack.push(zeichnung.getTransform());
}
public void popMatrix() {
if( transformStack.isEmpty() ) {
resetMatrix();
} else {
zeichnung.setTransform(transformStack.pop());
}
}
public void resetMatrix() {
zeichnung.setTransform(new AffineTransform());
}
}

View File

@@ -0,0 +1,313 @@
package schule.ngb.zm;
import schule.ngb.zm.formen.Formenebene;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import java.awt.*;
import java.awt.event.*;
public class Zeichenfenster extends Konstanten implements Runnable, MouseInputListener, KeyListener {
protected Object mouseLock = new Object();
/*
* Attribute für den Zugriff aus Unterklassen.
*/
protected Leinwand leinwand;
protected Zeichenebene zeichnung;
protected Formenebene formen;
protected int tick = 0;
protected long laufzeit = 0L;
protected double delta = 0.0;
protected double mausX = 0.0, mausY = 0.0, lmausX = 0.0, lmausY = 0.0;
protected int breite = STD_BREITE, hoehe = STD_HOEHE;
/*
* Interne Attribute zur Steuerung der Zeichenamschine.
*/
//
private JFrame frame;
private boolean running = false;
private int framesPerSecond;
public Zeichenfenster() {
this(APP_NAME);
}
public Zeichenfenster( String pTitel ) {
this(STD_BREITE, STD_HOEHE, pTitel);
}
public Zeichenfenster( int pBreite, int pHoehe, String pTitel ) {
frame = new JFrame(pTitel);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch( Exception e ) {
System.err.println("Fehler beim Setzen des look and feel.");
}
breite = pBreite;
hoehe = pHoehe;
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
leinwand = new Leinwand(pBreite, pHoehe);
frame.setContentPane(leinwand);
framesPerSecond = STD_FPS;
zeichnung = getZeichenEbene();
formen = getFormenEbene();
einstellungen();
frame.addMouseListener(this);
frame.addMouseMotionListener(this);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing( WindowEvent e ) {
running = false;
super.windowClosing(e);
}
});
frame.pack();
frame.requestFocusInWindow();
frame.setVisible(true);
running = true;
new Thread(this).start();
}
public final void setSize( int pWidth, int pHeight ) {
//frame.setSize(pWidth, pHeight);
if( leinwand != null ) {
leinwand.setSize(pWidth, pHeight);
}
breite = pWidth;
hoehe = pHeight;
frame.pack();
}
public final int getBreite() {
return breite;
}
public final int getHoehe() {
return hoehe;
}
public final void setTitel( String pTitel ) {
frame.setTitle(pTitel);
}
public final Leinwand getLeinwand() {
return leinwand;
}
public final void hinzu( Ebene pEbene ) {
leinwand.hinzu(pEbene);
}
public final Zeichenebene getZeichenEbene() {
Zeichenebene layer = leinwand.getEbene(Zeichenebene.class);
if( layer == null ) {
layer = new Zeichenebene(getBreite(), getHoehe());
leinwand.hinzu(0, layer);
}
return layer;
}
public final Formenebene getFormenEbene() {
Formenebene layer = leinwand.getEbene(Formenebene.class);
if( layer == null ) {
layer = new Formenebene(getBreite(), getHoehe());
leinwand.hinzu(layer);
}
return layer;
}
public final int getFramesPerSecond() {
return framesPerSecond;
}
public final void setFramesPerSecond( int pFramesPerSecond ) {
framesPerSecond = pFramesPerSecond;
}
@Override
public final void run() {
long start = System.currentTimeMillis();
long current = System.nanoTime();
int _tick = 0;
long _runtime = 0;
tick = 0;
laufzeit = 0;
vorbereiten();
while( running ) {
int dt = (int) ((System.nanoTime() - current) / 1E6);
current = System.nanoTime();
delta = (dt / 1000.0);
saveMousePosition();
aktualisieren(delta);
zeichnen();
if( leinwand != null ) {
//drawing.invalidate();
frame.repaint();
}
try {
int sleep = Math.round(1000 / framesPerSecond);
if( dt >= sleep ) {
sleep -= dt % sleep;
}
Thread.sleep(Math.max(0, sleep));
} catch( InterruptedException e ) {
// Interrupt not relevant
} finally {
_tick += 1;
_runtime = System.currentTimeMillis() - start;
tick = _tick;
laufzeit = _runtime;
}
}
}
/*
* Methoden, die von Unterklassen überschrieben werden können / sollen.
*/
public void einstellungen() {
}
public void vorbereiten() {
}
public void zeichnen() {
}
public void aktualisieren( double delta ) {
running = false;
}
/*
* Mouse handling
*/
@Override
public void mouseClicked( MouseEvent e ) {
saveMousePosition(e.getPoint());
mausklick();
}
public void mausklick() {
}
@Override
public void mousePressed( MouseEvent e ) {
saveMousePosition(e.getPoint());
maustasteRunter();
}
public void maustasteRunter() {
}
@Override
public void mouseReleased( MouseEvent e ) {
saveMousePosition(e.getPoint());
maustasteHoch();
}
public void maustasteHoch() {
}
@Override
public void mouseEntered( MouseEvent e ) {
saveMousePosition(e.getPoint());
}
@Override
public void mouseExited( MouseEvent e ) {
saveMousePosition(e.getPoint());
}
@Override
public void mouseDragged( MouseEvent e ) {
saveMousePosition(e.getPoint());
mausGezogen();
}
public void mausGezogen() {
}
@Override
public void mouseMoved( MouseEvent e ) {
saveMousePosition(e.getPoint());
mausBewegt();
}
public void mausBewegt() {
}
private void saveMousePosition( Point pLocation ) {
//pmouseX = mouseX;
//pmouseY = mouseY;
/*synchronized(mouseLock) {
mouseX = pLocation.getX()-this.getRootPane().getX();
mouseY = pLocation.getY()-this.getRootPane().getY();
}*/
}
private void saveMousePosition() {
lmausX = mausX;
lmausY = mausY;
java.awt.Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
java.awt.Point compLoc = leinwand.getLocationOnScreen();
mausX = mouseLoc.x - compLoc.x;
mausY = mouseLoc.y - compLoc.y;
}
/*
* Keyboard handling
*/
@Override
public void keyTyped( KeyEvent e ) {
tastendruck();
}
public void tastendruck() {
}
@Override
public void keyPressed( KeyEvent e ) {
tasteRunter();
}
public void tasteRunter() {
}
@Override
public void keyReleased( KeyEvent e ) {
tasteHoch();
}
public void tasteHoch() {
}
}