diff --git a/src/schule/ngb/zm/Color.java b/src/schule/ngb/zm/Color.java
new file mode 100644
index 0000000..bc61db5
--- /dev/null
+++ b/src/schule/ngb/zm/Color.java
@@ -0,0 +1,280 @@
+package schule.ngb.zm;
+
+public class Color {
+
+ public static final Color BLACK = new Color(java.awt.Color.BLACK);
+
+ public static final Color WHITE = new Color(java.awt.Color.WHITE);
+
+ public static final Color GRAY = new Color(java.awt.Color.GRAY);
+
+ public static final Color DARKGRAY = new Color(java.awt.Color.DARK_GRAY);
+
+ public static final Color LIGHTGRAY = new Color(java.awt.Color.LIGHT_GRAY);
+
+ public static final Color RED = new Color(java.awt.Color.RED);
+
+ public static final Color GREEN = new Color(java.awt.Color.GREEN);
+
+ public static final Color BLUE = new Color(java.awt.Color.BLUE);
+
+ public static final Color YELLOW = new Color(java.awt.Color.YELLOW);
+
+ public static final Color ORANGE = new Color(java.awt.Color.ORANGE);
+
+ public static final Color CYAN = new Color(java.awt.Color.CYAN);
+
+ public static final Color MAGENTA = new Color(java.awt.Color.MAGENTA);
+
+ public static final Color PINK = new Color(java.awt.Color.PINK);
+
+ public static final Color HGGREEN = new Color(0, 165, 81);
+
+ public static final Color HGRED = new Color(151, 54, 60);
+
+
+ private int rgba;
+
+ public Color() {
+ rgba = 0xFF000000;
+ }
+
+ public Color( int gray ) {
+ this(gray, gray, gray, 255);
+ }
+
+ public Color( int gray, int alpha ) {
+ this(gray, gray, gray, alpha);
+ }
+
+ public Color( int red, int green, int blue ) {
+ this(red, green, blue, 255);
+ }
+
+ public Color( int red, int green, int blue, int alpha ) {
+ rgba = (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ public Color( Color color ) {
+ this(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
+ }
+
+ public Color( Color color, int alpha ) {
+ this(color.getRed(), color.getGreen(), color.getBlue(), alpha);
+ }
+
+ public Color( java.awt.Color color ) {
+ this(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
+ }
+
+ public Color( java.awt.Color color, int alpha ) {
+ this(color.getRed(), color.getGreen(), color.getBlue(), alpha);
+ }
+
+ public static Color parseRGB( int rgba ) {
+ Color c = new Color();
+ c.rgba = rgba;
+ return c;
+ }
+
+ public static Color parseHexcode( String hexcode ) {
+ if( hexcode.startsWith("#") ) {
+ hexcode = hexcode.substring(1);
+ }
+ if( hexcode.length() != 3 && hexcode.length() != 6 && hexcode.length() != 8 ) {
+ throw new IllegalArgumentException("color hexcodes have to be 3, 6 or 8 digits long, got " + hexcode.length());
+ }
+
+ // normalize hexcode to 8 digits
+ int alpha = 255;
+ if( hexcode.length() == 3 ) {
+ hexcode = "" + hexcode.charAt(0) + hexcode.charAt(0) + hexcode.charAt(1) + hexcode.charAt(1) + hexcode.charAt(2) + hexcode.charAt(2);
+ } else if( hexcode.length() == 8 ) {
+ alpha = Integer.valueOf(hexcode.substring(6, 8), 16);
+ hexcode = hexcode.substring(0, 6);
+ } else {
+ hexcode = hexcode;
+ }
+
+ Color c = new Color();
+ c.rgba = (alpha << 24) | Integer.valueOf(hexcode, 16);
+ return c;
+ }
+
+ public static Color morph( java.awt.Color pFarbe1, java.awt.Color pFarbe2, double pFactor ) {
+ if( pFactor < 0.0 || pFarbe2 == null ) {
+ return new Color(pFarbe1);
+ }
+ if( pFactor > 1.0 || pFarbe1 == null ) return new Color(pFarbe2);
+ double pFactorInv = 1 - pFactor;
+ return new Color((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 static float[] RGBtoHSL( int rgb, float[] hsl ) {
+ float r = ((rgb >> 16) & 255) / 255.0f;
+ float g = ((rgb >> 8) & 255) / 255.0f;
+ float b = (rgb & 255) / 255.0f;
+ float max = Math.max(Math.max(r, g), b);
+ float min = Math.min(Math.min(r, g), b);
+ float c = max - min;
+
+ if( hsl == null ) {
+ hsl = new float[3];
+ }
+
+ float h_ = 0.f;
+ if( c == 0 ) {
+ h_ = 0;
+ } else if( max == r ) {
+ h_ = (float) (g - b) / c;
+ if( h_ < 0 ) h_ += 6.f;
+ } else if( max == g ) {
+ h_ = (float) (b - r) / c + 2.f;
+ } else if( max == b ) {
+ h_ = (float) (r - g) / c + 4.f;
+ }
+ float h = 60.f * h_;
+
+ float l = (max + min) * 0.5f;
+
+ float s;
+ if( c == 0 ) {
+ s = 0.f;
+ } else {
+ s = c / (1 - Math.abs(2.f * l - 1.f));
+ }
+
+ hsl[0] = h;
+ hsl[1] = s;
+ hsl[2] = l;
+ return hsl;
+ }
+
+ public static int HSLtoRGB( float[] hsl ) {
+ return HSLtoRGB(hsl, 255);
+ }
+
+ public static int HSLtoRGB( float[] hsl, int alpha ) {
+ float h = hsl[0];
+ float s = hsl[1];
+ float l = hsl[2];
+
+ float c = (1 - Math.abs(2.f * l - 1.f)) * s;
+ float h_ = h / 60.f;
+ float h_mod2 = h_;
+ if( h_mod2 >= 4.f ) h_mod2 -= 4.f;
+ else if( h_mod2 >= 2.f ) h_mod2 -= 2.f;
+
+ float x = c * (1 - Math.abs(h_mod2 - 1));
+ float r_, g_, b_;
+ if( h_ < 1 ) {
+ r_ = c;
+ g_ = x;
+ b_ = 0;
+ } else if( h_ < 2 ) {
+ r_ = x;
+ g_ = c;
+ b_ = 0;
+ } else if( h_ < 3 ) {
+ r_ = 0;
+ g_ = c;
+ b_ = x;
+ } else if( h_ < 4 ) {
+ r_ = 0;
+ g_ = x;
+ b_ = c;
+ } else if( h_ < 5 ) {
+ r_ = x;
+ g_ = 0;
+ b_ = c;
+ } else {
+ r_ = c;
+ g_ = 0;
+ b_ = x;
+ }
+
+ float m = l - (0.5f * c);
+ int r = (int) ((r_ + m) * (255.f) + 0.5f);
+ int g = (int) ((g_ + m) * (255.f) + 0.5f);
+ int b = (int) ((b_ + m) * (255.f) + 0.5f);
+ return (alpha & 255) << 24 | r << 16 | g << 8 | b;
+ }
+
+ /*public void setRed( int red ) {
+ rgba = (red << 16) | (0xFF00FFFF & rgba);
+ }*/
+
+ public Color copy() {
+ return new Color(this);
+ }
+
+ /*public void setGreen( int green ) {
+ rgba = (green << 8) | (0xFFFF00FF & rgba);
+ }*/
+
+ public int getRGBA() {
+ return rgba;
+ }
+
+ /*public void setBlue( int blue ) {
+ rgba = blue | (0xFFFFFF00 & rgba);
+ }*/
+
+ public int getRed() {
+ return (rgba >> 16) & 255;
+ }
+
+ /*public void setAlpha( int alpha ) {
+ rgba = (alpha << 24) | (0x00FFFFFF & rgba);
+ }*/
+
+ public int getGreen() {
+ return (rgba >> 8) & 255;
+ }
+
+ public int getBlue() {
+ return rgba & 255;
+ }
+
+ public int getAlpha() {
+ return (rgba >> 24) & 255;
+ }
+
+ public java.awt.Color getColor() {
+ return new java.awt.Color(rgba, true);
+ }
+
+ @Override
+ public boolean equals( Object po ) {
+ if( this == po ) return true;
+ if( po == null || getClass() != po.getClass() ) return false;
+ Color ppColor = (Color) po;
+ return rgba == ppColor.rgba;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getCanonicalName() + '[' + "r=" + getRed() + ',' + "g=" + getGreen() + ',' + "b=" + getBlue() + ',' + "a=" + getAlpha() + ']';
+ }
+
+ public Color brighter() {
+ return brighter(30);
+ }
+
+ public Color brighter( int percent ) {
+ float[] hsl = RGBtoHSL(rgba, null);
+ hsl[2] = Math.min(Math.max(hsl[2] * (1.0f + percent / 100.0f), 0.0f), 1.0f);
+ return Color.parseRGB(HSLtoRGB(hsl, getAlpha()));
+ }
+
+ public Color darker() {
+ return darker(30);
+ }
+
+ public Color darker( int percent ) {
+ float[] hsl = RGBtoHSL(rgba, null);
+ hsl[2] = Math.min(Math.max(hsl[2] * (1.0f - percent / 100.0f), 0.0f), 1.0f);
+ return Color.parseRGB(HSLtoRGB(hsl, getAlpha()));
+ }
+
+}
diff --git a/src/schule/ngb/zm/ColorLayer.java b/src/schule/ngb/zm/ColorLayer.java
new file mode 100644
index 0000000..5ef5f6d
--- /dev/null
+++ b/src/schule/ngb/zm/ColorLayer.java
@@ -0,0 +1,18 @@
+package schule.ngb.zm;
+
+public class ColorLayer extends Layer {
+
+ private Color background;
+
+ public ColorLayer( Color color ) {
+ this.background = color;
+ clear();
+ }
+
+ @Override
+ public void clear() {
+ drawing.setColor(background.getColor());
+ drawing.fillRect(0, 0, getWidth(), getHeight());
+ }
+
+}
diff --git a/src/schule/ngb/zm/Constants.java b/src/schule/ngb/zm/Constants.java
new file mode 100644
index 0000000..d79e9ee
--- /dev/null
+++ b/src/schule/ngb/zm/Constants.java
@@ -0,0 +1,208 @@
+package schule.ngb.zm;
+
+import java.util.Random;
+
+public class Constants {
+
+ public static final String APP_NAME = "Zeichenmaschine";
+
+ public static final int APP_VERSION_MAJ = 0;
+
+ public static final int APP_VERSION_MIN = 1;
+
+ public static final int APP_VERSION_REV = 5;
+
+ public static final String APP_VERSION = APP_VERSION_MAJ + "." + APP_VERSION_MIN + "." + APP_VERSION_REV;
+
+ public static final int STD_WIDTH = 400;
+
+ public static final int STD_HEIGHT = 400;
+
+ public static final int STD_FPS = 60;
+
+ public static final Color STD_FILLCOLOR = Color.WHITE;
+
+ public static final Color STD_STROKECOLOR = Color.BLACK;
+
+ public static final double STD_STROKEWEIGHT = 1.0;
+
+ public static final int STD_FONTSIZE = 14;
+
+ public static final Options.StrokeType SOLID = Options.StrokeType.SOLID;
+
+ public static final Options.StrokeType DASHED = Options.StrokeType.DASHED;
+
+ public static final Options.StrokeType DOTTED = Options.StrokeType.DOTTED;
+
+ public static final Options.ArrowHead LINES = Options.ArrowHead.LINES;
+
+ public static final Options.ArrowHead FILLED = Options.ArrowHead.FILLED;
+
+ public static final Options.PathType OPEN = Options.PathType.OPEN;
+
+ public static final Options.PathType CLOSED = Options.PathType.CLOSED;
+
+ public static final Options.PathType PIE = Options.PathType.PIE;
+
+ public static final Options.Direction CENTER = Options.Direction.CENTER;
+
+ public static final Options.Direction NORTH = Options.Direction.NORTH;
+
+ public static final Options.Direction EAST = Options.Direction.EAST;
+
+ public static final Options.Direction SOUTH = Options.Direction.SOUTH;
+
+ public static final Options.Direction WEST = Options.Direction.WEST;
+
+ public static final Options.Direction NORTHEAST = Options.Direction.NORTHEAST;
+
+ public static final Options.Direction SOUTHEAST = Options.Direction.SOUTHEAST;
+
+ public static final Options.Direction NORTHWEST = Options.Direction.NORTHWEST;
+
+ public static final Options.Direction SOUTHWEST = Options.Direction.SOUTHWEST;
+
+ public static final Options.Direction MIDDLE = Options.Direction.MIDDLE;
+
+ public static final Options.Direction UP = Options.Direction.UP;
+
+ public static final Options.Direction RIGHT = Options.Direction.RIGHT;
+
+ public static final Options.Direction DOWN = Options.Direction.DOWN;
+
+ public static final Options.Direction LEFT = Options.Direction.LEFT;
+
+ public static final Color BLACK = Color.BLACK;
+
+ public static final Color WHITE = Color.WHITE;
+
+ public static final Color RED = Color.RED;
+
+ public static final Color BLUE = Color.BLUE;
+
+ public static final Color GREEN = Color.GREEN;
+
+ public static final Color YELLOW = Color.YELLOW;
+
+ public static Color STD_BACKGROUND = new Color(200, 200, 200);
+
+ public static Color color( int gray ) {
+ return color(gray, gray, gray, 255);
+ }
+
+ public static Color color( int gray, int alpha ) {
+ return color(gray, gray, gray, alpha);
+ }
+
+ public static Color color( int red, int green, int blue ) {
+ return color(red, green, blue, 255);
+ }
+
+ public static Color color( 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 Color(red, green, blue, alpha);
+ }
+
+
+ public static double abs( double x ) {
+ return Math.abs(x);
+ }
+
+ public static double sign( double x ) {
+ return Math.signum(x);
+ }
+
+ public static double round( double x ) {
+ return Math.round(x);
+ }
+
+ public static double floor( double x ) {
+ return Math.floor(x);
+ }
+
+ public static double ceil( double x ) {
+ return Math.ceil(x);
+ }
+
+ public static double sin( double x ) {
+ return Math.sin(x);
+ }
+
+ public static double cos( double x ) {
+ return Math.cos(x);
+ }
+
+ public static double tan( double x ) {
+ return Math.tan(x);
+ }
+
+ public static double arcsin( double x ) {
+ return Math.asin(x);
+ }
+
+ public static double arccos( double x ) {
+ return Math.acos(x);
+ }
+
+ public static double arctan( double x ) {
+ return Math.atan(x);
+ }
+
+ public static double limit( double x, double max ) {
+ if( x > max ) {
+ return max;
+ }
+ return x;
+ }
+
+ public static double limit( double x, double min, double max ) {
+ if( x > max ) {
+ return max;
+ }
+ if( x < min ) {
+ return min;
+ }
+ return x;
+ }
+
+ public static double morph( double from, double to, double t ) {
+ return from - t * (from + to);
+ }
+
+ public static double random( double min, double max ) {
+ return Math.random() * (max - min) + min;
+ }
+
+ public static int random( int min, int max ) {
+ return (int) (Math.random() * (max - min) + min);
+ }
+
+ public static boolean randomBool() {
+ return randomBool(.5);
+ }
+
+ public static boolean randomBool( int percent ) {
+ return randomBool(percent / 100.0);
+ }
+
+ public static boolean randomBool( double weight ) {
+ return Math.random() < weight;
+ }
+
+ public static double randomGuassian() {
+ return new Random().nextGaussian();
+ }
+
+ public static double noise() {
+ return 0.0;
+ }
+
+}
diff --git a/src/schule/ngb/zm/Zeichenbar.java b/src/schule/ngb/zm/Drawable.java
similarity index 85%
rename from src/schule/ngb/zm/Zeichenbar.java
rename to src/schule/ngb/zm/Drawable.java
index 6aa79fa..3511f73 100644
--- a/src/schule/ngb/zm/Zeichenbar.java
+++ b/src/schule/ngb/zm/Drawable.java
@@ -6,7 +6,7 @@ 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 {
+public interface Drawable {
/**
* Gibt an, ob das Objekt derzeit sichtbar ist (also gezeichnet werden
@@ -14,11 +14,11 @@ public interface Zeichenbar {
*
* @return true, wenn das Objekt sichtbar ist.
*/
- public boolean istSichtbar();
+ boolean isVisible();
/**
* Wird aufgerufen, um das Objekt auf die Zeichenfläche graphics
- * zu zeichnen.
+ * zu draw.
*
* Das Objekt muss dafür Sorge tragen, dass der Zustand der Zeichenfläche
* (Transformationsmatrix, Farbe, ...) erhalten bleibt. Das Objekt sollte
@@ -26,6 +26,6 @@ public interface Zeichenbar {
*
* @param graphics Die Zeichenfläche.
*/
- public void zeichnen( Graphics2D graphics );
+ void draw( Graphics2D graphics );
}
diff --git a/src/schule/ngb/zm/DrawingLayer.java b/src/schule/ngb/zm/DrawingLayer.java
new file mode 100644
index 0000000..34b8548
--- /dev/null
+++ b/src/schule/ngb/zm/DrawingLayer.java
@@ -0,0 +1,525 @@
+package schule.ngb.zm;
+
+import schule.ngb.zm.util.ImageLoader;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.Stack;
+
+public class DrawingLayer extends Layer {
+
+ protected Color strokeColor;
+
+ protected Color fillColor;
+
+ protected double strokeWeight;
+
+ protected Options.StrokeType strokeType = SOLID;
+
+ private Options.Direction default_anchor = CENTER;
+
+ protected Line2D.Double line = new Line2D.Double();
+ protected Ellipse2D.Double ellipse = new Ellipse2D.Double();
+ protected Rectangle2D.Double rect = new Rectangle2D.Double();
+ protected Arc2D.Double arc = new Arc2D.Double();
+
+ private Stack transformStack = new Stack<>();
+
+ private FontMetrics fontMetrics = null;
+
+ public DrawingLayer() {
+ super();
+ transformStack.push(new AffineTransform());
+
+ strokeColor = Color.BLACK;
+ fillColor = Color.WHITE;
+ strokeWeight = 1.0;
+
+ fontMetrics = drawing.getFontMetrics();
+ }
+
+ public DrawingLayer( int width, int height ) {
+ super(width, height);
+ }
+
+ public Color getColor() {
+ return fillColor;
+ }
+
+ public void setColor( int gray ) {
+ setColor(gray, gray, gray, 255);
+ }
+
+ public void setColor( Color color ) {
+ fillColor = color;
+ drawing.setColor(color.getColor());
+ }
+
+ public void noFill() {
+ fillColor = null;
+ }
+
+ 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 ) {
+ setColor(new Color(red, green, blue, alpha));
+ }
+
+ public Color getStrokeColor() {
+ return strokeColor;
+ }
+
+ public void setStrokeColor( int gray ) {
+ setStrokeColor(gray, gray, gray, 255);
+ }
+
+ public void setStrokeColor( Color color ) {
+ strokeColor = color;
+ drawing.setColor(color.getColor());
+ }
+
+ public void noStroke() {
+ strokeColor = null;
+ }
+
+ public void setStrokeColor( int gray, int alpha ) {
+ setStrokeColor(gray, gray, gray, alpha);
+ }
+
+ public void setStrokeColor( int red, int green, int blue ) {
+ setStrokeColor(red, green, blue, 255);
+ }
+
+ public void setStrokeColor( int red, int green, int blue, int alpha ) {
+ setStrokeColor(new Color(red, green, blue, alpha));
+ }
+
+ public void setStrokeWeight( double pWeight ) {
+ strokeWeight = pWeight;
+ drawing.setStroke(createStroke());
+ }
+
+ protected Stroke createStroke() {
+ switch( strokeType ) {
+ case DOTTED:
+ return new BasicStroke(
+ (float) strokeWeight,
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND,
+ 10.0f, new float[]{1.0f, 5.0f}, 0.0f);
+ case DASHED:
+ 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 Options.StrokeType getStrokeType() {
+ return strokeType;
+ }
+
+ public void setStrokeType( Options.StrokeType type ) {
+ switch( type ) {
+ case DASHED:
+ this.strokeType = DASHED;
+ break;
+ case DOTTED:
+ this.strokeType = DOTTED;
+ break;
+ default:
+ this.strokeType = SOLID;
+ break;
+ }
+ }
+
+ public void resetStroke() {
+ setStrokeColor(STD_STROKECOLOR);
+ setStrokeWeight(STD_STROKEWEIGHT);
+ setStrokeType(SOLID);
+ }
+
+ public void setAnchor( Options.Direction anchor ) {
+ default_anchor = anchor;
+ }
+
+ 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());*/
+ java.awt.Color currentColor = drawing.getColor();
+ pushMatrix();
+ resetMatrix();
+ drawing.setColor(pColor.getColor());
+ drawing.fillRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ drawing.setColor(currentColor);
+ popMatrix();
+ }
+
+ public void line( double x1, double y1, double x2, double y2 ) {
+ //Shape line = new Line2D.Double(x1, y1, x2, y2);
+ line.setLine(x1, y1, x2, y2);
+ 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, Options.Direction 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, Options.Direction anchor ) {
+ Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
+ // Shape rect = new Rectangle2D.Double(anchorPoint.getX(), anchorPoint.getY(), w, h);
+ rect.setRect(anchorPoint.getX(), anchorPoint.getY(), w, h);
+ 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, Options.Direction 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, Options.Direction anchor ) {
+ Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
+ // Shape ellipse = new Ellipse2D.Double(anchorPoint.x, anchorPoint.y, w, h);
+ ellipse.setFrame(anchorPoint.x, anchorPoint.y, w, h);
+ 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, CENTER);
+ /*Shape arc = new Arc2D.Double(
+ anchorPoint.x,
+ anchorPoint.y,
+ d, d,
+ angle1, angle2 - angle1,
+ Arc2D.OPEN
+ );*/
+ arc.setArc(
+ anchorPoint.x, anchorPoint.y,
+ d, d,
+ angle1, angle2 - angle1,
+ Arc2D.OPEN
+ );
+
+ 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, CENTER);
+ /*Shape arc = new Arc2D.Double(
+ anchorPoint.x,
+ anchorPoint.y,
+ d, d,
+ angle1, angle2 - angle1,
+ Arc2D.PIE
+ );*/
+ arc.setArc(
+ anchorPoint.x, anchorPoint.y,
+ d, d,
+ angle1, angle2 - angle1,
+ Arc2D.PIE
+ );
+
+ fillShape(arc);
+ drawShape(arc);
+ }
+
+ public void curve( double x1, double y1, double x2, double y2, double x3, double y3 ) {
+ QuadCurve2D curve = new QuadCurve2D.Double(x1, y1, x2, y2, x3, y3);
+ drawShape(curve);
+ }
+
+ public void curve( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 ) {
+ CubicCurve2D curve = new CubicCurve2D.Double(x1, y1, x2, y2, x3, y3, x4, y4);
+ drawShape(curve);
+ }
+
+ public void triangle( double x1, double y1, double x2, double y2, double x3, double y3 ) {
+ Path2D path = new Path2D.Double();
+ path.moveTo(x1, y1);
+ path.lineTo(x2, y2);
+ path.lineTo(x3, y3);
+ path.lineTo(x1, y1);
+
+ fillShape(path);
+ drawShape(path);
+ }
+
+ public void rhombus( double x, double y, double width, double height ) {
+ rhombus(x, y, width, height, default_anchor);
+ }
+
+ public void rhombus( double x, double y, double width, double height, Options.Direction anchor ) {
+ double whalf = width / 2.0, hhalf = height / 2.0;
+ Point2D.Double anchorPoint = getAnchorPoint(x, y, width, height, anchor);
+ polygon(anchorPoint.x + whalf, anchorPoint.y, anchorPoint.x + width, anchorPoint.y + hhalf, anchorPoint.x + whalf, anchorPoint.y + height, anchorPoint.x, anchorPoint.y + hhalf);
+ }
+
+ public void polygon( double... coordinates ) {
+ if( coordinates.length < 4 ) {
+ return;
+ }
+
+ Path2D path = new Path2D.Double();
+ path.moveTo(coordinates[0], coordinates[1]);
+ for( int i = 2; i < coordinates.length; i += 2 ) {
+ if( i + 1 < coordinates.length ) {
+ path.lineTo(coordinates[i], coordinates[i + 1]);
+ }
+ }
+
+ int len = coordinates.length;
+ if( coordinates[len - 2] != coordinates[0] || coordinates[len - 1] != coordinates[1] ) {
+ path.lineTo(coordinates[0], coordinates[1]);
+ }
+
+ fillShape(path);
+ drawShape(path);
+ }
+
+ public void polygon( Point2D... points ) {
+ if( points.length < 2 ) {
+ return;
+ }
+
+ Path2D path = new Path2D.Double();
+ path.moveTo(points[0].getX(), points[0].getY());
+ for( int i = 1; i < points.length; i += 1 ) {
+ path.lineTo(points[i].getX(), points[i].getY());
+ }
+
+ int len = points.length;
+ if( points[len - 1].equals(points[0]) ) {
+ path.moveTo(points[0].getX(), points[0].getY());
+ }
+
+ fillShape(path);
+ drawShape(path);
+ }
+
+ public void image( String imageSource, double x, double y ) {
+ image(ImageLoader.loadImage(imageSource), x, y, 1.0, default_anchor);
+ }
+
+ public void image( String imageSource, double x, double y, Options.Direction anchor ) {
+ image(ImageLoader.loadImage(imageSource), x, y, 1.0, anchor);
+ }
+
+ public void image( String imageSource, double x, double y, double scale ) {
+ image(ImageLoader.loadImage(imageSource), x, y, scale, default_anchor);
+ }
+
+ public void image( String imageSource, double x, double y, double scale, Options.Direction anchor ) {
+ image(ImageLoader.loadImage(imageSource), x, y, scale, anchor);
+ }
+
+ public void image( Image image, double x, double y ) {
+ image(image, x, y, 1.0, default_anchor);
+ }
+
+ public void image( Image image, double x, double y, double scale ) {
+ image(image, x, y, scale, default_anchor);
+ }
+
+ public void image( Image image, double x, double y, double scale, Options.Direction anchor ) {
+ if( image != null ) {
+ double neww = image.getWidth(null) * scale;
+ double newh = image.getHeight(null) * scale;
+ Point2D.Double anchorPoint = getAnchorPoint(x, y, neww, newh, anchor);
+ drawing.drawImage(image, (int) anchorPoint.x, (int) anchorPoint.y, (int) neww, (int) newh, null);
+ }
+ }
+
+ public void text( String text, double x, double y ) {
+ text(text, x, y, default_anchor);
+ }
+
+ public void text( String text, double x, double y, Options.Direction anchor ) {
+ FontMetrics fm = drawing.getFontMetrics();
+ Point2D.Double anchorPoint = getAnchorPoint(x, y + fm.getAscent(), fm.stringWidth(text), fm.getHeight(), anchor);
+
+ drawing.drawString(text, (float) anchorPoint.x, (float) anchorPoint.y);
+ }
+
+ public void setFontSize( int size ) {
+ setFont(drawing.getFont().deriveFont((float)size));
+ }
+
+ public void setFont( String fontName ) {
+ Font font = new Font(fontName, drawing.getFont().getStyle(), drawing.getFont().getSize());
+ setFont(font);
+ }
+
+ public void setFont( String fontName, int size ) {
+ Font font = new Font(fontName, drawing.getFont().getStyle(), size);
+ setFont(font);
+ }
+
+ public void setFont( String fontName, int size, int style ) {
+ Font font = new Font(fontName, style, size);
+ setFont(font);
+ }
+
+ public void setFont( Font font ) {
+ drawing.setFont(font);
+ fontMetrics = drawing.getFontMetrics();
+ }
+
+
+ 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 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 Point2D.Double getAnchorPoint( double x, double y, double w, double h, Options.Direction anchor ) {
+ double whalf = w * .5, hhalf = h * .5;
+
+ // anchor == CENTER
+ Point2D.Double anchorPoint = new Point2D.Double(x - whalf, y - hhalf);
+
+ if( NORTH.is(anchor) ) {
+ anchorPoint.y += hhalf;
+ }
+ if( SOUTH.is(anchor) ) {
+ anchorPoint.y -= hhalf;
+ }
+ if( WEST.is(anchor) ) {
+ anchorPoint.x += whalf;
+ }
+ if( EAST.is(anchor) ) {
+ anchorPoint.x -= whalf;
+ }
+
+ return anchorPoint;
+ }
+
+ private void fillShape( Shape pShape ) {
+ if( fillColor != null && fillColor.getAlpha() > 0.0 ) {
+ drawing.setColor(fillColor.getColor());
+ drawing.fill(pShape);
+ }
+ }
+
+ private void drawShape( Shape pShape ) {
+ if( strokeColor != null && strokeColor.getAlpha() > 0.0
+ && strokeWeight > 0.0 ) {
+ drawing.setColor(strokeColor.getColor());
+ drawing.setStroke(createStroke());
+ drawing.draw(pShape);
+ }
+ }
+
+ public void translate( double dx, double dy ) {
+ drawing.translate(dx, dy);
+ }
+
+ public void scale( double factor ) {
+ drawing.scale(factor, factor);
+ }
+
+ public void rotate( double pAngle ) {
+ drawing.rotate(Math.toRadians(pAngle));
+ }
+
+ public void shear( double dx, double dy ) {
+ drawing.shear(dx, dy);
+ }
+
+ public AffineTransform getMatrix() {
+ return drawing.getTransform();
+ }
+
+ public void pushMatrix() {
+ transformStack.push(drawing.getTransform());
+ }
+
+ public void popMatrix() {
+ if( transformStack.isEmpty() ) {
+ resetMatrix();
+ } else {
+ drawing.setTransform(transformStack.pop());
+ }
+ }
+
+ public void resetMatrix() {
+ drawing.setTransform(new AffineTransform());
+ }
+
+}
diff --git a/src/schule/ngb/zm/Ebene.java b/src/schule/ngb/zm/Ebene.java
deleted file mode 100644
index fd64ccf..0000000
--- a/src/schule/ngb/zm/Ebene.java
+++ /dev/null
@@ -1,106 +0,0 @@
-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;
- }
-
-}
diff --git a/src/schule/ngb/zm/Farbe.java b/src/schule/ngb/zm/Farbe.java
deleted file mode 100644
index 2c2327f..0000000
--- a/src/schule/ngb/zm/Farbe.java
+++ /dev/null
@@ -1,95 +0,0 @@
-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);
- }
-
-}
diff --git a/src/schule/ngb/zm/ImageLayer.java b/src/schule/ngb/zm/ImageLayer.java
new file mode 100644
index 0000000..e64c87d
--- /dev/null
+++ b/src/schule/ngb/zm/ImageLayer.java
@@ -0,0 +1,75 @@
+package schule.ngb.zm;
+
+import schule.ngb.zm.util.ImageLoader;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ImageObserver;
+
+public class ImageLayer extends Layer {
+
+ protected Image image;
+
+ protected double x = 0;
+
+ protected double y = 0;
+
+ protected boolean redraw = true;
+
+ public ImageLayer() {
+
+ }
+
+
+ public ImageLayer( String source ) {
+ image = ImageLoader.loadImage(source);
+ }
+
+ public ImageLayer( Image image ) {
+ this.image = image;
+ }
+
+ public ImageLayer( int width, int height, Image image ) {
+ super(width, height);
+ this.image = image;
+ }
+
+ public void setImage( Image image ) {
+ this.image = image;
+ redraw = true;
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public void setX( double pX ) {
+ this.x = pX;
+ redraw = true;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public void setY( double pY ) {
+ this.y = pY;
+ redraw = true;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ redraw = true;
+ }
+
+ @Override
+ public void draw( Graphics2D graphics ) {
+ if( redraw && visible ) {
+ drawing.drawImage(image, (int)x, (int)y, null);
+ redraw = false;
+ }
+ super.draw(graphics);
+ }
+
+}
diff --git a/src/schule/ngb/zm/Konstanten.java b/src/schule/ngb/zm/Konstanten.java
deleted file mode 100644
index 87b6d23..0000000
--- a/src/schule/ngb/zm/Konstanten.java
+++ /dev/null
@@ -1,145 +0,0 @@
-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);
- }
-
-}
diff --git a/src/schule/ngb/zm/Layer.java b/src/schule/ngb/zm/Layer.java
new file mode 100644
index 0000000..d81f702
--- /dev/null
+++ b/src/schule/ngb/zm/Layer.java
@@ -0,0 +1,138 @@
+package schule.ngb.zm;
+
+import java.awt.Color;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+public abstract class Layer extends Constants implements Drawable, Updatable {
+
+ protected BufferedImage buffer;
+
+ protected Graphics2D drawing;
+
+ protected boolean visible = true;
+
+ protected boolean active = true;
+
+
+ public Layer() {
+ this(STD_WIDTH, STD_HEIGHT);
+ }
+
+ public Layer( int width, int height ) {
+ createCanvas(width, height);
+ }
+
+ public int getWidth() {
+ return buffer.getWidth();
+ }
+
+ public int getHeight() {
+ return buffer.getHeight();
+ }
+
+ public void setSize( int width, int height ) {
+ if( buffer != null ) {
+ if( buffer.getWidth() != width || buffer.getHeight() != height ) {
+ recreateCanvas(width, height);
+ }
+ } else {
+ createCanvas(width, height);
+ }
+
+ }
+
+ public void dispose() {
+ drawing.dispose();
+ }
+
+ /**
+ * Erstellt einen neuen Puffer für die Ebene und konfiguriert diesen.
+ *
+ * @param width Width des neuen Puffers.
+ * @param height Höhe des neuen Puffers.
+ */
+ private void createCanvas( int width, int height ) {
+ buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ drawing = buffer.createGraphics();
+
+ // add antialiasing
+ RenderingHints hints = new RenderingHints(
+ RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON
+ );
+ hints.put(
+ RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON
+ );
+ hints.put(
+ RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY
+ );
+ drawing.addRenderingHints(hints);
+ }
+
+ /**
+ * Erstellt einen neuen Puffer für dei Ebene mit der angegebenen Größe
+ * und kopiert den Inhalt des alten Puffers in den Neuen.
+ *
+ * @param width Width des neuen Puffers.
+ * @param height Höhe des neuen Puffers.
+ */
+ private void recreateCanvas( int width, int height ) {
+ BufferedImage oldCanvas = buffer;
+ createCanvas(width, height);
+ drawing.drawImage(oldCanvas, 0, 0, null);
+ }
+
+ /**
+ * Leert die Ebene und löscht alles bisher gezeichnete. Alle Pixel der
+ * Ebene werden transparent, damit unterliegende Ebenen durchscheinen können.
+ */
+ public void clear() {
+ // https://stackoverflow.com/questions/31149206/set-pixels-of-bufferedimage-as-transparent
+ drawing.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
+ drawing.setColor(new Color(255, 255, 255, 255));
+ drawing.fillRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ drawing.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+ }
+
+ /**
+ * Zeichnet den Puffer auf die Grafik-Instanz.
+ *
+ * @param pGraphics
+ */
+ @Override
+ public void draw( Graphics2D pGraphics ) {
+ if( visible ) {
+ pGraphics.drawImage(buffer, 0, 0, null);
+ }
+ }
+
+ @Override
+ public boolean isVisible() {
+ return visible;
+ }
+
+ public void hide() {
+ visible = false;
+ }
+
+ public void view() {
+ visible = true;
+ }
+
+ public void toggle() {
+ visible = !visible;
+ }
+
+ @Override
+ public void update( double delta ) {
+ }
+
+ @Override
+ public boolean isActive() {
+ return active;
+ }
+
+}
diff --git a/src/schule/ngb/zm/Leinwand.java b/src/schule/ngb/zm/Leinwand.java
deleted file mode 100644
index fe6040d..0000000
--- a/src/schule/ngb/zm/Leinwand.java
+++ /dev/null
@@ -1,118 +0,0 @@
-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 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 getEbenen() {
- return ebenen;
- }
-
- /**
- * Holt die {@link Ebene} am Index i (beginnend bei 0).
- *
- * @param i Index der Ebene (beginnend bei 0).
- * @return Die Ebene am Index i oder null.
- * @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 null zurückgegeben.
- *
- * @param pClazz Typ der Ebene.
- * @param
- * @return Erste Ebene vom angegeben Typ.
- */
- public L getEbene( Class pClazz ) {
- for( Ebene ebene : ebenen ) {
- if( ebene.getClass().equals(pClazz) ) {
- return pClazz.cast(ebene);
- }
- }
- return null;
- }
-
- public java.util.List getEbenen( Class pClazz ) {
- ArrayList 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();
- }
-}
diff --git a/src/schule/ngb/zm/Options.java b/src/schule/ngb/zm/Options.java
new file mode 100644
index 0000000..7207bfe
--- /dev/null
+++ b/src/schule/ngb/zm/Options.java
@@ -0,0 +1,67 @@
+package schule.ngb.zm;
+
+import java.awt.geom.Arc2D;
+
+/**
+ * Diese Klasse sammelt Enumerationen, die verschiedene Eigenschaften der
+ * zu zeichnenden Formen darstellen.
+ */
+public final class Options {
+ private Options() {}
+
+ public enum StrokeType {
+ SOLID, DASHED, DOTTED
+ }
+
+ public enum ArrowHead {
+ LINES, FILLED
+ }
+
+ public enum PathType {
+ OPEN(Arc2D.OPEN), CLOSED(Arc2D.CHORD), PIE(Arc2D.PIE);
+ public final int awt_type;
+ PathType( int type ) {
+ awt_type = type;
+ }
+ }
+
+ public enum AppState {
+ INITIALIZING,
+ INITIALIZED,
+ RUNNING,
+ AUSED,
+ STOPPED,
+ TERMINATED
+ }
+
+ public enum Direction {
+ CENTER(0),
+ NORTH(1 << 0),
+ EAST(1 << 1),
+ SOUTH(1 << 2),
+ WEST(1 << 3),
+
+ NORTHEAST(NORTH.mask | EAST.mask),
+ SOUTHEAST(SOUTH.mask | EAST.mask),
+ NORTHWEST(NORTH.mask | WEST.mask),
+ SOUTHWEST(SOUTH.mask | WEST.mask),
+
+ MIDDLE(CENTER.mask),
+ UP(NORTH.mask),
+ DOWN(SOUTH.mask),
+ LEFT(WEST.mask),
+ RIGHT(EAST.mask);
+
+ public final byte mask;
+ Direction( int mask ) {
+ this.mask = (byte) mask;
+ }
+ public boolean is( int mask ) {
+ return (mask & this.mask) == this.mask;
+ }
+ public boolean is( Direction dir ) {
+ return (dir.mask & this.mask) == this.mask;
+ }
+ }
+
+}
diff --git a/src/schule/ngb/zm/Shape2DLayer.java b/src/schule/ngb/zm/Shape2DLayer.java
new file mode 100644
index 0000000..2beed75
--- /dev/null
+++ b/src/schule/ngb/zm/Shape2DLayer.java
@@ -0,0 +1,166 @@
+package schule.ngb.zm;
+
+import java.awt.*;
+import java.util.LinkedList;
+
+public final class Shape2DLayer extends Layer {
+
+ protected Color strokeColor = STD_STROKECOLOR;
+
+ protected Color fillColor = STD_FILLCOLOR;
+
+ protected double strokeWeight = STD_STROKEWEIGHT;
+
+ protected Options.StrokeType strokeType = SOLID;
+
+ private LinkedList shapes;
+
+ private boolean instantDraw = false;
+
+ public Shape2DLayer() {
+ super();
+ shapes = new LinkedList();
+ }
+
+ public Shape2DLayer( boolean instantDraw ) {
+ super();
+ shapes = new LinkedList();
+ this.instantDraw = instantDraw;
+ }
+
+ public Shape2DLayer( int width, int height ) {
+ super(width, height);
+ shapes = new LinkedList();
+ }
+
+ public Shape2DLayer( int width, int height, boolean instantDraw ) {
+ super(width, height);
+ shapes = new LinkedList();
+ this.instantDraw = instantDraw;
+ }
+
+ public Color getFillColor() {
+ return fillColor;
+ }
+
+ public void setFillColor( int gray ) {
+ setFillColor(gray, gray, gray, 255);
+ }
+
+ public void setFillColor( Color pColor ) {
+ fillColor = pColor;
+ drawing.setColor(pColor.getColor());
+ }
+
+ public void noFill() {
+ fillColor = null;
+ }
+
+ public void setFillColor( int gray, int alpha ) {
+ setFillColor(gray, gray, gray, alpha);
+ }
+
+ public void setFillColor( int red, int green, int blue ) {
+ setFillColor(red, green, blue, 255);
+ }
+
+ public void setFillColor( int red, int green, int blue, int alpha ) {
+ setFillColor(new Color(red, green, blue, alpha));
+ }
+
+ public Color getStrokeColor() {
+ return strokeColor;
+ }
+
+ public void setStrokeColor( int gray ) {
+ setStrokeColor(gray, gray, gray, 255);
+ }
+
+ public void setStrokeColor( Color pColor ) {
+ strokeColor = pColor;
+ drawing.setColor(pColor.getColor());
+ }
+
+ public void noStroke() {
+ strokeColor = null;
+ }
+
+ public void setStrokeColor( int gray, int alpha ) {
+ setStrokeColor(gray, gray, gray, alpha);
+ }
+
+ public void setStrokeColor( int red, int green, int blue ) {
+ setStrokeColor(red, green, blue, 255);
+ }
+
+ public void setStrokeColor( int red, int green, int blue, int alpha ) {
+ setStrokeColor(new Color(red, green, blue, alpha));
+ }
+
+ public void setStrokeWeight( double pWeight ) {
+ strokeWeight = pWeight;
+ drawing.setStroke(createStroke());
+ }
+
+ protected Stroke createStroke() {
+ switch( strokeType ) {
+ case DOTTED:
+ return new BasicStroke(
+ (float) strokeWeight,
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND,
+ 10.0f, new float[]{1.0f, 5.0f}, 0.0f);
+ case DASHED:
+ 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 Options.StrokeType getStrokeType() {
+ return strokeType;
+ }
+
+ public void setStrokeType( Options.StrokeType strokeType ) {
+ this.strokeType = strokeType;
+ }
+
+ public java.util.List getShapes() {
+ return shapes;
+ }
+
+ public void add( java.awt.Shape s ) {
+ shapes.add(s);
+
+ if( instantDraw ) {
+ drawing.setColor(fillColor.getColor());
+ drawing.fill(s);
+
+ drawing.setColor(strokeColor.getColor());
+ drawing.draw(s);
+ }
+ }
+
+ @Override
+ public void draw( Graphics2D pGraphics ) {
+ if( !instantDraw ) {
+ for( Shape shape : shapes ) {
+ drawing.setColor(fillColor.getColor());
+ drawing.fill(shape);
+
+ drawing.setColor(strokeColor.getColor());
+ drawing.draw(shape);
+ }
+ }
+
+ super.draw(pGraphics);
+ }
+
+}
diff --git a/src/schule/ngb/zm/Aktualisierbar.java b/src/schule/ngb/zm/Updatable.java
similarity index 72%
rename from src/schule/ngb/zm/Aktualisierbar.java
rename to src/schule/ngb/zm/Updatable.java
index 9841ecf..0a60447 100644
--- a/src/schule/ngb/zm/Aktualisierbar.java
+++ b/src/schule/ngb/zm/Updatable.java
@@ -2,22 +2,22 @@ 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
+ * pro Frame) ihren Zustand update. Diese Änderung kann abhängig vom
* Zeitintervall (in Sekunden) zum letzten Aufruf passieren.
*/
-public interface Aktualisierbar {
+public interface Updatable {
/**
* Gibt an, ob das Objekt gerade auf Aktualisierungen reagiert.
* @return true, wenn das Objekt aktiv ist.
*/
- public boolean istAktiv();
+ public boolean isActive();
/**
* Änderung des Zustandes des Objekts abhängig vom Zeitintervall
* delta in Sekunden.
* @param delta Zeitintervall seit dem letzten Aufruf (in Sekunden).
*/
- public void aktualisieren( double delta );
+ public void update( double delta );
}
diff --git a/src/schule/ngb/zm/Vector.java b/src/schule/ngb/zm/Vector.java
new file mode 100644
index 0000000..453a84f
--- /dev/null
+++ b/src/schule/ngb/zm/Vector.java
@@ -0,0 +1,253 @@
+package schule.ngb.zm;
+
+import java.awt.geom.Point2D;
+
+public class Vector extends Point2D.Double {
+
+ public static final Vector UP = new Vector(0, -1.0);
+ public static final Vector DOWN = new Vector(0, 1.0);
+ public static final Vector RIGHT = new Vector(1.0, 0);
+ public static final Vector LEFT = new Vector(-1.0, -1.0);
+
+
+ public Vector() {
+ x = 0.0;
+ y = 0.0;
+ }
+
+ public Vector( double x, double pY ) {
+ this.x = x;
+ y = pY;
+ }
+
+ public Vector( Point2D point ) {
+ x = point.getX();
+ x = point.getY();
+ }
+
+ public Vector( Vector vec ) {
+ x = vec.x;
+ y = vec.y;
+ }
+
+ public static Vector random() {
+ return new Vector(Math.random() * 100, Math.random() * 100);
+ }
+
+ public static Vector random( double min, double max ) {
+ return new Vector(Math.random() * (max - min) + min, Math.random() * (max - min) + min);
+ }
+
+ public static Vector setLength( Vector vector, double length ) {
+ Vector vec = vector.copy();
+ vec.setLen(length);
+ return vec;
+ }
+
+ public static Vector normalize( Vector vector ) {
+ Vector vec = vector.copy();
+ vec.normalize();
+ return vec;
+ }
+
+ public static Vector add( Vector vector1, Vector vector2 ) {
+ Vector vec = vector1.copy();
+ vec.add(vector2);
+ return vec;
+ }
+
+ public static Vector sub( Vector vector1, Vector vector2 ) {
+ Vector vec = vector1.copy();
+ vec.sub(vector2);
+ return vec;
+ }
+
+ public static Vector scale( Vector vector, double scalar ) {
+ Vector vec = vector.copy();
+ vec.scale(scalar);
+ return vec;
+ }
+
+ public static Vector div( Vector vector, double scalar ) {
+ Vector vec = vector.copy();
+ vec.div(scalar);
+ return vec;
+ }
+
+ public static double dist( Vector vector1, Vector vector2 ) {
+ return vector1.dist(vector2);
+ }
+
+ public static double dot( Vector vector1, Vector vector2 ) {
+ return vector1.dot(vector2);
+ }
+
+ public static double cross( Vector vector1, Vector vector2 ) {
+ return vector1.cross(vector2);
+ }
+
+ public static Vector rotate( Vector vector, double degree ) {
+ Vector vec = vector.copy();
+ vec.rotate(degree);
+ return vec;
+ }
+
+ public static Vector morph( Vector vector1, Vector vector2, float t ) {
+ Vector vec = vector1.copy();
+ vec.morph(vector2, t);
+ return vec;
+ }
+
+ public Vector copy() {
+ return new Vector(x, y);
+ }
+
+ public Vector set( double x, double y ) {
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ public Vector set( Vector vector ) {
+ x = vector.x;
+ y = vector.y;
+ return this;
+ }
+
+ public Vector set( Point2D pPunkt ) {
+ x = pPunkt.getX();
+ x = pPunkt.getY();
+ return this;
+ }
+
+ public void setX( double x ) {
+ this.x = x;
+ }
+
+ public void setY( double y ) {
+ this.y = y;
+ }
+
+ public Point2D getPunkt() {
+ return new Point2D.Double(x, y);
+ }
+
+ public double len() {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ public double lenSq() {
+ return x * x + y * y;
+ }
+
+ public Vector setLen( double length ) {
+ normalize();
+ return scale(length);
+ }
+
+ public Vector normalize() {
+ double len = len();
+ if( len != 0 && len != 1 ) {
+ x /= len;
+ y /= len;
+ }
+ return this;
+ }
+
+ public Vector add( Vector vector ) {
+ x += vector.x;
+ y += vector.y;
+ return this;
+ }
+
+ public Vector add( double x, double y ) {
+ this.x += x;
+ this.y += y;
+ return this;
+ }
+
+ public Vector sub( Vector vector ) {
+ x -= vector.x;
+ y -= vector.y;
+ return this;
+ }
+
+ public Vector sub( double x, double y ) {
+ this.x -= x;
+ this.y -= y;
+ return this;
+ }
+
+ public Vector scale( double scalar ) {
+ x *= scalar;
+ y *= scalar;
+ return this;
+ }
+
+ public Vector div( double scalar ) {
+ x /= scalar;
+ y /= scalar;
+ return this;
+ }
+
+ public double dist( Vector vector ) {
+ double dx = x - vector.x;
+ double dy = y - vector.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double dot( Vector vector ) {
+ return x * vector.x + y * vector.y;
+ }
+
+ public double dot( double x, double y ) {
+ return this.x * x + this.y * y;
+ }
+
+ // See: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
+ public double cross( Vector vector ) {
+ return x * vector.y - vector.x * y;
+ }
+
+ public Vector limit( double max ) {
+ if( lenSq() > max * max ) {
+ setLen(max);
+ }
+ return this;
+ }
+
+ public Vector limit( double min, double max ) {
+ if( min > max ) {
+ throw new IllegalArgumentException("HVector.constrain(): pMin muss kleiner sein als pMax.");
+ }
+ if( lenSq() < min * min ) {
+ setLen(min);
+ } else if( lenSq() > min * min ) {
+ setLen(max);
+ }
+ return this;
+ }
+
+ public double angle() {
+ double angle = Math.atan2(y, x);
+ return Math.toDegrees(angle);
+ }
+
+ public Vector rotate( double degree ) {
+ double temp = x, rad = Math.toRadians(degree);
+ x = x * Math.cos(rad) - y * Math.sin(rad);
+ y = temp * Math.sin(rad) + y * Math.cos(rad);
+ return this;
+ }
+
+ public void morph( Vector vector, float t ) {
+ x = x + (vector.x - x) * t;
+ y = y + (vector.y - y) * t;
+ }
+
+ @Override
+ public String toString() {
+ return "schule.ngb.zm.Vector[x = " + x + ", y = " + y + "]";
+ }
+
+}
diff --git a/src/schule/ngb/zm/Vektor.java b/src/schule/ngb/zm/Vektor.java
deleted file mode 100644
index edfd1af..0000000
--- a/src/schule/ngb/zm/Vektor.java
+++ /dev/null
@@ -1,251 +0,0 @@
-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 + "}";
- }
-
-}
diff --git a/src/schule/ngb/zm/Zeichenebene.java b/src/schule/ngb/zm/Zeichenebene.java
deleted file mode 100644
index b6000c7..0000000
--- a/src/schule/ngb/zm/Zeichenebene.java
+++ /dev/null
@@ -1,417 +0,0 @@
-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 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());
- }
-
-}
diff --git a/src/schule/ngb/zm/Zeichenleinwand.java b/src/schule/ngb/zm/Zeichenleinwand.java
new file mode 100644
index 0000000..b77809f
--- /dev/null
+++ b/src/schule/ngb/zm/Zeichenleinwand.java
@@ -0,0 +1,195 @@
+package schule.ngb.zm;
+
+import schule.ngb.zm.formen.ShapesLayer;
+
+import java.awt.*;
+import java.awt.image.BufferStrategy;
+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 aNORTHen, ausblenden oder wieder
+ * löschen.
+ *
+ * Jede Ebene besitzt eine Zeichenfläche, auf der ihre Zeichnung liegt. Diese
+ * zeichenflächen werden pro Frame einmal von "DOWN" nach "UP" auf diese
+ * Leinwand gezeichnet.
+ */
+public class Zeichenleinwand extends Canvas {
+
+ private LinkedList layers;
+
+ public Zeichenleinwand( int width, int height ) {
+ super.setSize(width, height);
+ this.setPreferredSize(this.getSize());
+ this.setMinimumSize(this.getSize());
+ this.setBackground(Constants.STD_BACKGROUND.getColor());
+
+ // Liste der Ebenen initialisieren und die Standardebenen einfügen
+ layers = new LinkedList<>();
+ layers.add(new ColorLayer(Constants.STD_BACKGROUND));
+ layers.add(new DrawingLayer());
+ layers.add(new ShapesLayer());
+ }
+
+ /**
+ * Ändert die Größe der Zeichenleinwand auf die angegebene Größe in Pixeln.
+ * Eine Größenänderung hat auch eine Größenänderung aller Ebenen zur Folge.
+ *
+ * @param width Neue Width der Leinwand in Pixeln.
+ * @param height Neue Höhe der Leinwand in Pixeln.
+ */
+ @Override
+ public void setSize( int width, int height ) {
+ super.setSize(width, height);
+ this.setPreferredSize(this.getSize());
+ this.setMinimumSize(this.getSize());
+
+ for( Layer layer : layers ) {
+ layer.setSize(width, height);
+ }
+ }
+
+ /**
+ * Fügt der Zeichenleinwand eine Ebene hinzu, die oberhalb aller bisherigen
+ * Ebenen eingefügt wird.
+ * @param layer Die neue Ebene.
+ */
+ public void addLayer( Layer layer ) {
+ if( layer != null ) {
+ layer.setSize(getWidth(), getHeight());
+ layers.add(layer);
+ }
+ }
+
+ /**
+ * Fügt der Zeichenleinwand eine Ebene an einer bestimmten Stelle hinzu.
+ * @param i Index der Ebene, beginnend mit 0.
+ * @param layer Die neue Ebene.
+ */
+ public void addLayer( int i, Layer layer ) {
+ if( layer != null ) {
+ layer.setSize(getWidth(), getHeight());
+ layers.add(i, layer);
+ }
+ }
+
+ /**
+ * Gibt die Liste der bisher hinzugefügten Ebenen zurück.
+ * @return Liste der Ebenen.
+ */
+ public java.util.List getLayers() {
+ return layers;
+ }
+
+ /**
+ * Holt die Ebene am Index i (beginnend bei 0).
+ *
+ * @param i Index der Ebene (beginnend bei 0).
+ * @return Die Ebene am Index i oder null.
+ * @throws IndexOutOfBoundsException Falls der Index nicht existiert.
+ */
+ public Layer getLayer( int i ) {
+ if( layers.size() > i ) {
+ return layers.get(i);
+ } else {
+ throw new IndexOutOfBoundsException("No layer at index " + i + " (max: " + (layers.size() - 1) + ").");
+ }
+ }
+
+ /**
+ * Sucht die erste Ebene des angegebenen Typs aus der Liste der Ebenen.
+ * Existiert keine solche Ebene, wird null zurückgegeben.
+ *
+ * @param clazz Typ der Ebene.
+ * @param
+ * @return Erste Ebene vom angegeben Typ.
+ */
+ public L getLayer( Class clazz ) {
+ for( Layer layer : layers ) {
+ if( layer.getClass().equals(clazz) ) {
+ return clazz.cast(layer);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sucht alle Ebenen von einem bestimmten Typ aus der Liste der Ebenen und
+ * gibt diese als Liste zurück. Die Reihenfolge in der Liste entspricht der
+ * Reihenfolge der Ebenen in der Leinwand (von unten nach oben).
+ *
+ * @param pClazz
+ * @param
+ * @return
+ */
+ public java.util.List getLayers( Class pClazz ) {
+ ArrayList result = new ArrayList<>(layers.size());
+ for( Layer layer : layers ) {
+ if( layer.getClass().equals(pClazz) ) {
+ result.add(pClazz.cast(layer));
+ }
+ }
+ return result;
+ }
+
+ public void allocateBuffer() {
+ this.createBufferStrategy(2);
+ }
+
+ public void dispose() {
+ for( Layer layer : layers ) {
+ layer.dispose();
+ }
+ }
+
+ @Override
+ public void paint( Graphics g ) {
+ render();
+ }
+
+ public void render() {
+ if( getBufferStrategy() == null ) {
+ allocateBuffer();
+ }
+
+ if( isDisplayable() ) {
+ BufferStrategy strategy = this.getBufferStrategy();
+ if( strategy != null ) {
+ do {
+ do {
+ Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
+ g2d.clearRect(0, 0, getWidth(), getHeight());
+
+ for( Layer layer : layers ) {
+ layer.draw(g2d);
+ }
+
+ g2d.dispose();
+ } while( strategy.contentsRestored() );
+
+ // Display the buffer
+ if (!strategy.contentsLost()) {
+ strategy.show();
+
+ Toolkit.getDefaultToolkit().sync();
+ }
+
+ // Repeat the rendering if the drawing buffer was lost
+ } while( strategy.contentsLost() );
+ }
+
+ /*
+ Graphics2D g2d = (Graphics2D) g.create();
+
+ for( Layer layer : layers ) {
+ layer.draw(g2d);
+ }
+
+ g2d.dispose();
+ */
+ }
+ }
+}
diff --git a/src/schule/ngb/zm/Zeichenmaschine.java b/src/schule/ngb/zm/Zeichenmaschine.java
new file mode 100644
index 0000000..e202435
--- /dev/null
+++ b/src/schule/ngb/zm/Zeichenmaschine.java
@@ -0,0 +1,471 @@
+package schule.ngb.zm;
+
+import schule.ngb.zm.formen.ShapesLayer;
+
+import javax.swing.*;
+import javax.swing.event.MouseInputListener;
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * Hauptklasse der Zeichenmaschine.
+ *
+ * Projekte der Zeichenmaschine sollten als Unterklasse implementiert werden.
+ * Die Klasse übernimmt die Initialisierung eines Programmfensters und der
+ * nötigen Komponenten.
+ */
+public class Zeichenmaschine extends Constants implements MouseInputListener, KeyListener {
+
+ public static boolean IN_BLUEJ;
+
+ static {
+ IN_BLUEJ = System.getProperty("java.class.path").contains("bluej");
+ }
+
+ /*
+ * Attributes to be accessed by subclasses.
+ */
+ protected Zeichenleinwand canvas;
+
+ protected DrawingLayer drawing;
+
+ protected ShapesLayer shapes;
+
+ protected int tick = 0;
+
+ protected long runtime = 0L;
+
+ protected double delta = 0.0;
+
+ protected double mouseX = 0.0, mouseY = 0.0, pmouseX = 0.0, pmouseY = 0.0;
+
+ protected int width = STD_WIDTH, height = STD_HEIGHT;
+
+ private Object mouseLock = new Object();
+
+ private Object keyboardLock = new Object();
+
+ /*
+ * Internal attributes for controlling the sketchmachine
+ * Interne Attribute zur Steuerung der Zeichenamschine.
+ */
+ //
+ private JFrame frame;
+
+ private boolean running = false, isDrawing = false, isUpdating = false;
+
+ private int framesPerSecond;
+
+ private Thread mainThread;
+
+ private boolean quitAfterTeardown = false, initialized = false;
+
+ public Zeichenmaschine() {
+ this(APP_NAME + " " + APP_VERSION);
+ }
+
+ public Zeichenmaschine( String title ) {
+ this(STD_WIDTH, STD_HEIGHT, title);
+ }
+
+ public Zeichenmaschine( int width, int height, String title ) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch( Exception e ) {
+ System.err.println("Error setting the look and feel.");
+ }
+
+ GraphicsEnvironment environment =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice displayDevice = environment.getDefaultScreenDevice();
+
+ frame = new JFrame(displayDevice.getDefaultConfiguration());
+ frame.setTitle(title);
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+
+ this.width = width;
+ this.height = height;
+
+ canvas = new Zeichenleinwand(width, height);
+ frame.add(canvas);
+
+ framesPerSecond = STD_FPS;
+
+ drawing = getDrawingLayer();
+ shapes = getShapesLayer();
+
+ settings();
+
+ canvas.addMouseListener(this);
+ canvas.addMouseMotionListener(this);
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing( WindowEvent e ) {
+ if( running ) {
+ running = false;
+ quitAfterTeardown = true;
+ } else {
+ quit();
+ }
+ }
+ });
+
+ frame.pack();
+ frame.setResizable(false);
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+
+ canvas.allocateBuffer();
+
+ running = true;
+ mainThread = new Zeichenthread();
+ mainThread.start();
+
+ //frame.requestFocusInWindow();
+ canvas.requestFocus();
+
+ initialized = true;
+ }
+
+
+ public final void createFrame( String title ) {
+
+ }
+
+ public void show() {
+ if( !frame.isVisible() ) {
+ frame.setVisible(true);
+ }
+ }
+
+ public void hide() {
+ if( frame.isVisible() ) {
+ frame.setVisible(false);
+ }
+ }
+
+ public void quit() {
+ quit(!IN_BLUEJ);
+ }
+
+ public void quit( boolean exit ) {
+ frame.setVisible(false);
+ canvas.dispose();
+ frame.dispose();
+
+ if( exit ) {
+ System.exit(0);
+ }
+ }
+
+ public final void setSize( int width, int height ) {
+ //frame.setSize(width, height);
+
+ if( canvas != null ) {
+ canvas.setSize(width, height);
+ }
+ this.width = width;
+ this.height = height;
+ frame.pack();
+ }
+
+ public final int getWidth() {
+ return width;
+ }
+
+ public final int getHeight() {
+ return height;
+ }
+
+ public final void setTitle( String pTitel ) {
+ frame.setTitle(pTitel);
+ }
+
+ public final Zeichenleinwand getCanvas() {
+ return canvas;
+ }
+
+ public final void addLayer( Layer layer ) {
+ canvas.addLayer(layer);
+ }
+
+ public final DrawingLayer getDrawingLayer() {
+ DrawingLayer layer = canvas.getLayer(DrawingLayer.class);
+ if( layer == null ) {
+ layer = new DrawingLayer(getWidth(), getHeight());
+ canvas.addLayer(0, layer);
+ }
+ return layer;
+ }
+
+ public final ShapesLayer getShapesLayer() {
+ ShapesLayer layer = canvas.getLayer(ShapesLayer.class);
+ if( layer == null ) {
+ layer = new ShapesLayer(getWidth(), getHeight());
+ canvas.addLayer(layer);
+ }
+ return layer;
+ }
+
+ public final int getFramesPerSecond() {
+ return framesPerSecond;
+ }
+
+ public final void setFramesPerSecond( int pFramesPerSecond ) {
+ framesPerSecond = pFramesPerSecond;
+ }
+
+ /*
+ * Methoden, die von Unterklassen überschrieben werden können / sollen.
+ */
+ public void settings() {
+
+ }
+
+ public void setup() {
+
+ }
+
+ public void draw() {
+
+ }
+
+ public void teardown() {
+
+ }
+
+ public void update( double delta ) {
+ running = false;
+ }
+
+ public void delay( int ms ) {
+ if( ms <= 0 ) {
+ return;
+ }
+
+ long timer = 0L;
+ if( isDrawing ) {
+ // Immediately show the current drawing before waiting
+ // Measure the render time and subtract from the waiting ms
+ timer = System.nanoTime();
+ canvas.render();
+ timer = System.nanoTime() - timer;
+ }
+
+ try {
+ int sub = (int) Math.ceil(timer / 1000000.0);
+
+ if( sub >= ms ) {
+ return;
+ }
+
+ Thread.sleep(ms - sub, (int) (timer % 1000000L));
+ } catch( InterruptedException ex ) {
+ // Nothing
+ }
+ }
+
+ /*
+ * Mouse handling
+ */
+
+ @Override
+ public void mouseClicked( MouseEvent e ) {
+ saveMousePosition(e.getPoint());
+ mouseClicked();
+ }
+
+ public void mouseClicked() {
+ }
+
+ @Override
+ public void mousePressed( MouseEvent e ) {
+ saveMousePosition(e.getPoint());
+ mousePressed();
+ }
+
+ public void mousePressed() {
+ }
+
+ @Override
+ public void mouseReleased( MouseEvent e ) {
+ saveMousePosition(e.getPoint());
+ mouseReleased();
+ }
+
+ public void mouseReleased() {
+ }
+
+ @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());
+ mouseDragged();
+ }
+
+ public void mouseDragged() {
+
+ }
+
+ @Override
+ public void mouseMoved( MouseEvent e ) {
+ saveMousePosition(e.getPoint());
+ mouseMoved();
+ }
+
+ public void mouseMoved() {
+
+ }
+
+ 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() {
+ pmouseX = mouseX;
+ pmouseY = mouseY;
+
+ java.awt.Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
+ java.awt.Point compLoc = canvas.getLocationOnScreen();
+ mouseX = mouseLoc.x - compLoc.x;
+ mouseY = mouseLoc.y - compLoc.y;
+ }
+
+ @Override
+ public void keyTyped( KeyEvent e ) {
+ keyTyped();
+ }
+
+ /*
+ * Keyboard handling
+ */
+
+ public void keyTyped() {
+
+ }
+
+ @Override
+ public void keyPressed( KeyEvent e ) {
+ keyPressed();
+ }
+
+ public void keyPressed() {
+
+ }
+
+ @Override
+ public void keyReleased( KeyEvent e ) {
+ keyReleased();
+ }
+
+ public void keyReleased() {
+
+ }
+
+ class Zeichenthread extends Thread {
+
+ @Override
+ public final void run() {
+ // Wait for full initialization before start
+ while( !initialized ) {
+ delay(1);
+ }
+
+ // start of thread in ms
+ final long start = System.currentTimeMillis();
+ // current time in ns
+ long beforeTime = System.nanoTime();
+ // store for deltas
+ long overslept = 0L;
+ // internal counters for tick and runtime
+ int _tick = 0;
+ long _runtime = 0;
+ // public counters for access by subclasses
+ tick = 0;
+ runtime = 0;
+
+ // call setup of subclass
+ setup();
+
+ while( running ) {
+ // delta in seconds
+ delta = (System.nanoTime() - beforeTime) / 1000000000.0;
+ beforeTime = System.nanoTime();
+
+ saveMousePosition();
+
+ handleUpdate(delta);
+ handleDraw();
+
+ if( canvas != null ) {
+ canvas.render();
+ //canvas.invalidate();
+ //frame.repaint();
+ }
+
+ // delta time in ns
+ long afterTime = System.nanoTime();
+ long dt = afterTime - beforeTime;
+ long sleep = ((1000000000L / framesPerSecond) - dt) - overslept;
+
+
+ if( sleep > 0 ) {
+ try {
+ Thread.sleep(sleep / 1000000L, (int) (sleep % 1000000L));
+ } catch( InterruptedException e ) {
+ // Interrupt not relevant
+ }
+
+ overslept = (System.nanoTime() - afterTime) - sleep;
+ } else {
+ overslept = 0L;
+
+ }
+
+ _tick += 1;
+ _runtime = System.currentTimeMillis() - start;
+ tick = _tick;
+ runtime = _runtime;
+ }
+
+ teardown();
+ if( quitAfterTeardown ) {
+ quit();
+ }
+ }
+
+ public void handleUpdate( double delta ) {
+ if( isUpdating ) {
+ return;
+ }
+ isUpdating = true;
+ update(delta);
+ isUpdating = false;
+ }
+
+ public void handleDraw() {
+ if( isDrawing ) {
+ return;
+ }
+ isDrawing = true;
+ draw();
+ isDrawing = false;
+ }
+
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/AbgerundetesRechteck.java b/src/schule/ngb/zm/formen/AbgerundetesRechteck.java
deleted file mode 100644
index 49e9bff..0000000
--- a/src/schule/ngb/zm/formen/AbgerundetesRechteck.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-
-public class AbgerundetesRechteck extends Rechteck {
-
- protected double rundung = 1.0;
-
- public AbgerundetesRechteck( double pX, double pY, double pBreite, double pHoehe, double pRundung ) {
- super(pX, pY, pBreite, pHoehe);
- rundung = pRundung;
- }
-
- public AbgerundetesRechteck( Rechteck pRechteck ) {
- super(
- pRechteck.x, pRechteck.y,
- pRechteck.breite, pRechteck.hoehe);
- kopiere(pRechteck);
- }
-
- @Override
- public void kopiere( Form pForm ) {
- super.kopiere(pForm);
- if( pForm instanceof AbgerundetesRechteck ) {
- AbgerundetesRechteck rechteck = (AbgerundetesRechteck) pForm;
- rundung = rechteck.rundung;
- }
- }
-
- @Override
- public Shape getShape() {
- return new RoundRectangle2D.Double(
- 0, 0, breite, hoehe, rundung, rundung
- );
- }
-
- @Override
- public boolean equals( Object o ) {
- if( this == o ) return true;
- if( o == null || getClass() != o.getClass() ) return false;
- AbgerundetesRechteck rechteck = (AbgerundetesRechteck) o;
- return super.equals(o) &&
- Double.compare(rechteck.rundung, rundung) == 0;
- }
-
- @Override
- public String toString() {
- return getClass().getCanonicalName() + "[" +
- "x=" + x +
- ",y=" + y +
- ",breite=" + breite +
- ",hoehe=" + hoehe +
- ",rundung=" + rundung +
- ']';
- }
-
-}
diff --git a/src/schule/ngb/zm/formen/Arc.java b/src/schule/ngb/zm/formen/Arc.java
new file mode 100644
index 0000000..3752c1c
--- /dev/null
+++ b/src/schule/ngb/zm/formen/Arc.java
@@ -0,0 +1,111 @@
+package schule.ngb.zm.formen;
+
+import schule.ngb.zm.Options;
+
+import java.awt.geom.Arc2D;
+
+public class Arc extends Shape {
+
+ protected double width;
+
+ protected double height;
+
+ protected double angle;
+
+ protected double startingangle;
+
+ protected Options.PathType type = OPEN;
+
+ public Arc( double x, double y, double radius, double angle ) {
+ this(x, y, radius, radius, angle, 0.0);
+ }
+
+ public Arc( double x, double y, double radius, double angle, double startingangle ) {
+ this(x, y, radius, radius, angle, startingangle);
+ }
+
+ public Arc( double x, double y, double width, double height, double angle, double startingangle ) {
+ super(x, y);
+ this.width = width;
+ this.height = height;
+ this.angle = angle;
+ this.startingangle = startingangle;
+ setAnchor(CENTER);
+
+ noFill();
+ }
+
+ public Arc( Arc arc ) {
+ this(arc.x, arc.y, arc.width, arc.height, arc.angle, arc.startingangle);
+ copyFrom(arc);
+ }
+
+ public double getWidth() {
+ return width;
+ }
+
+ public void setWidth( double width ) {
+ this.width = width;
+ }
+
+ public double getHeight() {
+ return height;
+ }
+
+ public void setHeight( double height ) {
+ this.height = height;
+ }
+
+ public double getAngle() {
+ return angle;
+ }
+
+ public void setAngle( double angle ) {
+ this.angle = angle;
+ }
+
+ public double getStartingangle() {
+ return startingangle;
+ }
+
+ public void setStartingangle( double startingangle ) {
+ this.startingangle = startingangle;
+ }
+
+ public Options.PathType getType() {
+ return type;
+ }
+
+ public void setType( Options.PathType type ) {
+ this.type = type;
+ }
+
+ @Override
+ public Shape copy() {
+ return new Arc(this);
+ }
+
+ @Override
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof Arc ) {
+ Arc arc = (Arc) shape;
+ width = arc.width;
+ height = arc.height;
+ angle = arc.angle;
+ startingangle = arc.startingangle;
+ type = arc.type;
+ }
+ }
+
+ @Override
+ public void setAnchor( Options.Direction anchor ) {
+ calculateAnchor(width, height, anchor);
+ }
+
+ @Override
+ public java.awt.Shape getShape() {
+ return new Arc2D.Double(0, 0, width, height, startingangle, angle, type.awt_type);
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/Arrow.java b/src/schule/ngb/zm/formen/Arrow.java
new file mode 100644
index 0000000..556a4c0
--- /dev/null
+++ b/src/schule/ngb/zm/formen/Arrow.java
@@ -0,0 +1,178 @@
+package schule.ngb.zm.formen;
+
+import schule.ngb.zm.Options;
+import schule.ngb.zm.Vector;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+
+public class Arrow extends Line {
+
+ // Spitzenarten
+ public static final int OPEN = 101;
+
+ public static final int CLOSED = 102;
+
+ private static final double BASE_HEADSIZE = 5.0;
+
+ protected Options.ArrowHead arrowhead = LINES;
+
+ protected double headsize = 1.0;
+
+ public Arrow( double x1, double y1, double x2, double y2 ) {
+ super(x1, y1, x2, y2);
+ }
+
+ /**
+ * Erstellt einen Pfeil, der den übergebenen Vektor darstellt.
+ *
+ * @param vector
+ */
+ public Arrow( Vector vector ) {
+ this(0, 0, vector.x, vector.y);
+ }
+
+ /**
+ * Erstellt einen Pfeil, der den Differenzvektor zwischen den übergebenen
+ * Vektoren darstellt.
+ *
+ * @param vector1
+ * @param vector2
+ */
+ public Arrow( Vector vector1, Vector vector2 ) {
+ this(vector1.x, vector1.y, vector2.x, vector2.y);
+ }
+
+ /**
+ * Erstellt einen Pfeil, der den übergebenen Vektor um die angegeben
+ * Koordinaten verschoben darstellt.
+ *
+ * @param x
+ * @param y
+ * @param pVektor
+ */
+ public Arrow( double x, double y, Vector pVektor ) {
+ this(x, y, x + pVektor.x, y + pVektor.y);
+ }
+
+ /**
+ * Erstellt einen Pfeil als Kopie einer vorgegebenen Linie.
+ *
+ * @param pLine
+ */
+ public Arrow( Line pLine ) {
+ this(pLine.x, pLine.y, pLine.x2, pLine.y2);
+ this.copyFrom(pLine);
+ }
+
+ public double getHeadsize() {
+ return headsize;
+ }
+
+ public void setHeadsize( double headsize ) {
+ this.headsize = headsize;
+ }
+
+ public Options.ArrowHead getArrowhead() {
+ return arrowhead;
+ }
+
+ public void setArrowhead( Options.ArrowHead arrowhead ) {
+ this.arrowhead = arrowhead;
+ }
+
+ /**
+ * Kopiert die Werte des angegebenen Vektors.
+ *
+ * @param vector
+ */
+ public void copyFrom( Vector vector ) {
+ if( vector != null ) {
+ x2 = x + vector.x;
+ y2 = y + vector.y;
+ }
+ }
+
+ @Override
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof Arrow ) {
+ Arrow pArrow = (Arrow) shape;
+ headsize = pArrow.headsize;
+ arrowhead = pArrow.arrowhead;
+ }
+ }
+
+ @Override
+ public Arrow copy() {
+ return new Arrow(this);
+ }
+
+ @Override
+ public java.awt.Shape getShape() {
+ /*Path2D.Double gruppe = new Path2D.Double();
+ gruppe.append(super.getShape(), false);
+ gruppe.append(getPfeilspitze(), false);
+
+ return gruppe;*/
+ return super.getShape();
+ }
+
+ protected java.awt.Shape getHeadShape() {
+ AffineTransform af;
+ switch( arrowhead ) {
+ case LINES:
+ double len = BASE_HEADSIZE * headsize;
+ Path2D.Double sOPEN = new Path2D.Double();
+ sOPEN.moveTo(-len, -len);
+ sOPEN.lineTo(0, 0);
+ sOPEN.lineTo(-len, len);
+
+ af = new AffineTransform();
+ af.translate(x2-x, y2-y);
+ af.rotate(Math.atan2(y2 - y, x2 - x));
+ return af.createTransformedShape(sOPEN);
+ case FILLED:
+ default:
+ int ix = (int) x2, iy = (int) y2, pg = (int) (BASE_HEADSIZE * headsize);
+ java.awt.Polygon sCLOSED = new java.awt.Polygon(
+ new int[]{0, -pg, -pg},
+ new int[]{0, -pg, pg},
+ 3
+ );
+
+ af = new AffineTransform();
+ af.translate(x2-x, y2-y);
+ af.rotate(Math.atan2(y2 - y, x2 - x));
+ return af.createTransformedShape(sCLOSED);
+ }
+ }
+
+ @Override
+ public void draw( Graphics2D graphics, AffineTransform at ) {
+ if( !visible ) {
+ return;
+ }
+
+ super.draw(graphics, at);
+
+ java.awt.Shape head = getHeadShape();
+ if( at != null ) {
+ head = at.createTransformedShape(head);
+ }
+
+ Color currentColor = graphics.getColor();
+ if( strokeColor != null && strokeColor.getAlpha() > 0.0 ) {
+ graphics.setColor(strokeColor.getColor());
+ graphics.setStroke(new BasicStroke((float) strokeWeight));
+ if( arrowhead == FILLED ) {
+ graphics.fill(head);
+ } else {
+ graphics.draw(head);
+ }
+ }
+ graphics.setColor(currentColor);
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/Bild.java b/src/schule/ngb/zm/formen/Bild.java
deleted file mode 100644
index d9365f7..0000000
--- a/src/schule/ngb/zm/formen/Bild.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package schule.ngb.zm.formen;
-
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-
-public class Bild extends Form {
-
- private double breite;
-
- private double hoehe;
-
- private BufferedImage bild;
-
- public Bild( String pQuelle ) {
- this(0, 0, pQuelle);
- }
-
- public Bild( double pX, double pY, String pQuelle ) {
- super(pX, pY);
-
- if( pQuelle == null || pQuelle.length() == 0 )
- throw new IllegalArgumentException("Bildquelle darf nicht null oder leer sein.");
-
- try {
- // Bilddatei aus dem Arbeitsverzeichnis laden
- File file = new File(pQuelle);
- if( file.isFile() ) {
- bild = ImageIO.read(file);
- } else {
- // relativ zur .class-Datei
- URL url = getClass().getResource(pQuelle);
-
- // relativ zum ClassLoader
- if( url == null ) {
- url = getClass().getClassLoader().getResource(pQuelle);
- }
-
- // aWebadresse oder JAR-Datei
- if( url == null ) {
- url = new URL(pQuelle);
- }
-
- bild = ImageIO.read(url);
- }
-
- if( bild == null ) {
- throw new IllegalArgumentException("Bild konnte nicht aus " + pQuelle + " geladen werden!");
- }
-
- breite = bild.getWidth(null);
- hoehe = bild.getHeight(null);
- setAnkerpunkt(ZENTRUM);
- } catch( IOException ioe ) {
- throw new IllegalArgumentException("Bild konnte nicht aus " + pQuelle + " geladen werden!", ioe);
- }
- }
-
- public Bild( Bild pBild ) {
- super(pBild.getX(), pBild.getY());
- kopiere(pBild);
- }
-
- @Override
- public Form kopie() {
- return new Bild(this);
- }
-
- @Override
- public void kopiere( Form pForm ) {
- super.kopiere(pForm);
- if( pForm instanceof Bild ) {
- Bild pBild = (Bild)pForm;
- bild = new BufferedImage(pBild.bild.getWidth(), pBild.bild.getHeight(), pBild.bild.getType());
- Graphics2D g = bild.createGraphics();
- g.drawImage(pBild.bild, 0, 0, null);
- g.dispose();
-
- breite = bild.getWidth(null);
- hoehe = bild.getHeight(null);
- setAnkerpunkt(pForm.getAnkerpunkt());
- }
- }
-
- public double getBreite() {
- return breite;
- }
-
- public void setBreite( double pBreite ) {
- skalieren(pBreite / breite);
- }
-
- public double getHoehe() {
- return hoehe;
- }
-
- public void setHoehe( double pHoehe ) {
- skalieren(pHoehe / hoehe);
- }
-
- @Override
- public void setAnkerpunkt( byte pAnker ) {
- ankerBerechnen(breite, hoehe, pAnker);
- }
-
- @Override
- public void skalieren( double pFaktor ) {
- super.skalieren(pFaktor);
- breite *= pFaktor;
- hoehe *= pFaktor;
- }
-
- @Override
- public Shape getShape() {
- return new Rectangle2D.Double(0, 0, breite, hoehe);
- }
-
- /*
- @Override
- public AffineTransform getVerzerrung() {
- AffineTransform verzerrung = new AffineTransform();
- verzerrung.translate(x, y);
- verzerrung.scale(skalierung, skalierung);
- verzerrung.rotate(Math.toRadians(drehwinkel));
- verzerrung.translate(-anker.x, -anker.y);
- return verzerrung;
- }
- */
-
- @Override
- public void zeichnen( Graphics2D graphics, AffineTransform pVerzerrung ) {
- if( !sichtbar ) {
- return;
- }
-
- AffineTransform current = graphics.getTransform();
- graphics.transform(getVerzerrung());
- graphics.drawImage(bild, 0, 0, (int) breite, (int) hoehe, null);
- graphics.setTransform(current);
- }
-
-}
diff --git a/src/schule/ngb/zm/formen/Bogen.java b/src/schule/ngb/zm/formen/Bogen.java
deleted file mode 100644
index c4ef3f9..0000000
--- a/src/schule/ngb/zm/formen/Bogen.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.Arc2D;
-
-public class Bogen extends Form {
-
- protected double breite;
-
- protected double hoehe;
-
- protected double winkel;
-
- protected double startwinkel;
-
- protected int typ = OFFEN;
-
- public Bogen( double pX, double pY, double pRadius, double pWinkel ) {
- this(pX, pY, pRadius, pRadius, pWinkel, 0.0);
- }
-
- public Bogen( double pX, double pY, double pRadius, double pWinkel, double pStartwinkel ) {
- this(pX, pY, pRadius, pRadius, pWinkel, pStartwinkel);
- }
-
- public Bogen( double pX, double pY, double pBreite, double pHoehe, double pWinkel, double pStartwinkel ) {
- super(pX, pY);
- breite = pBreite;
- hoehe = pHoehe;
- winkel = pWinkel;
- startwinkel = pStartwinkel;
- setAnkerpunkt(ZENTRUM);
-
- keineFuellung();
- }
-
- public Bogen( Bogen pBogen ) {
- this(pBogen.x, pBogen.y, pBogen.breite, pBogen.hoehe, pBogen.winkel, pBogen.startwinkel);
- kopiere(pBogen);
- }
-
- public double getBreite() {
- return breite;
- }
-
- public void setBreite( double pBreite ) {
- this.breite = pBreite;
- }
-
- public double getHoehe() {
- return hoehe;
- }
-
- public void setHoehe( double pHoehe ) {
- this.hoehe = pHoehe;
- }
-
- public double getWinkel() {
- return winkel;
- }
-
- public void setWinkel( double pWinkel ) {
- this.winkel = pWinkel;
- }
-
- public double getStartwinkel() {
- return startwinkel;
- }
-
- public void setStartwinkel( double pStartwinkel ) {
- this.startwinkel = pStartwinkel;
- }
-
- public int getTyp() {
- return typ;
- }
-
- public void setTyp( int pTyp ) {
- this.typ = pTyp;
- }
-
- @Override
- public Form kopie() {
- return new Bogen(this);
- }
-
- @Override
- public void kopiere(Form pForm) {
- super.kopiere(pForm);
- if( pForm instanceof Bogen ) {
- Bogen b = (Bogen) pForm;
- breite = b.breite;
- hoehe = b.hoehe;
- winkel = b.winkel;
- startwinkel = b.startwinkel;
- typ = b.typ;
- }
- }
-
- @Override
- public void setAnkerpunkt( byte pAnker ) {
- ankerBerechnen(breite, hoehe, pAnker);
- }
-
- @Override
- public Shape getShape() {
- return new Arc2D.Double(0, 0, breite, hoehe, startwinkel, winkel, typ);
- }
-
-}
diff --git a/src/schule/ngb/zm/formen/Circle.java b/src/schule/ngb/zm/formen/Circle.java
new file mode 100644
index 0000000..8c614b0
--- /dev/null
+++ b/src/schule/ngb/zm/formen/Circle.java
@@ -0,0 +1,76 @@
+package schule.ngb.zm.formen;
+
+import schule.ngb.zm.Options;
+
+import java.awt.geom.Ellipse2D;
+
+public class Circle extends Shape {
+
+ protected double radius;
+
+ public Circle( double x, double y, double radius ) {
+ super(x, y);
+ this.radius = radius;
+ setAnchor(CENTER);
+ }
+
+ public Circle( Circle circle ) {
+ this(circle.x, circle.y, circle.radius);
+ copyFrom(circle);
+ }
+
+ public double getRadius() {
+ return radius;
+ }
+
+ public void setRadius( double radius ) {
+ this.radius = radius;
+ }
+
+ @Override
+ public void scale( double factor ) {
+ super.scale(factor);
+ radius *= factor;
+ }
+
+ @Override
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof Circle ) {
+ radius = ((Circle) shape).radius;
+ }
+ }
+
+ @Override
+ public Circle copy() {
+ return new Circle(this);
+ }
+
+ @Override
+ public java.awt.Shape getShape() {
+ return new Ellipse2D.Double(0, 0, radius + radius, radius + radius);
+ }
+
+ @Override
+ public void setAnchor( Options.Direction anchor ) {
+ calculateAnchor(radius + radius, radius + radius, anchor);
+ }
+
+ @Override
+ public boolean equals( Object o ) {
+ if( this == o ) return true;
+ if( o == null || getClass() != o.getClass() ) return false;
+ Circle pCircle = (Circle) o;
+ return super.equals(o) && Double.compare(pCircle.radius, radius) == 0;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getCanonicalName() + "[" +
+ "x=" + x +
+ ",y=" + y +
+ ",radius=" + radius +
+ ']';
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/Curve.java b/src/schule/ngb/zm/formen/Curve.java
new file mode 100644
index 0000000..1adfb34
--- /dev/null
+++ b/src/schule/ngb/zm/formen/Curve.java
@@ -0,0 +1,182 @@
+package schule.ngb.zm.formen;
+
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.util.Arrays;
+
+public class Curve extends Shape {
+
+ protected double[] coordinates;
+
+ public Curve( double x, double y, double cx, double cy, double x2, double y2 ) {
+ super(x, y);
+
+ coordinates = new double[]{
+ cx, cy, x2, y2
+ };
+
+ noFill();
+ }
+
+ public Curve( double x, double y, double cx1, double cy1, double cx2, double cy2, double x2, double y2 ) {
+ super(x, y);
+
+ coordinates = new double[]{
+ cx1, cy1, cx2, cy2, x2, y2
+ };
+
+ noFill();
+ }
+
+ public Curve( Curve curve ) {
+ super(curve.x, curve.y);
+ coordinates = Arrays.copyOf(curve.coordinates, curve.coordinates.length);
+ }
+
+ public Point2D getStart() {
+ return new Point2D.Double(x, y);
+ }
+
+ public void setStart( double x, double y ) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point2D getEnd() {
+ return new Point2D.Double(
+ coordinates[coordinates.length - 2],
+ coordinates[coordinates.length - 1]
+ );
+ }
+
+ public void setEnd( double x, double y ) {
+ coordinates[coordinates.length - 2] = x;
+ coordinates[coordinates.length - 1] = y;
+ }
+
+ public Point2D getControl1() {
+ return new Point2D.Double(
+ coordinates[0],
+ coordinates[1]
+ );
+ }
+
+ public void setControl1( double x, double y ) {
+ coordinates[0] = x;
+ coordinates[1] = y;
+ }
+
+ public Point2D getControl2() {
+ return new Point2D.Double(
+ coordinates[coordinates.length - 4],
+ coordinates[coordinates.length - 3]
+ );
+ }
+
+ public void setControl2( double x, double y ) {
+ coordinates[coordinates.length - 4] = x;
+ coordinates[coordinates.length - 3] = y;
+ }
+
+ public void setPoints( double x, double y, double cx, double cy, double x2, double y2 ) {
+ setStart(x, y);
+ coordinates = coordinates = new double[]{
+ cx, cy, x2, y2
+ };
+ }
+
+ public void setPoints( double x, double y, double cx1, double cy1, double cx2, double cy2, double x2, double y2 ) {
+ setStart(x, y);
+ coordinates = new double[]{
+ cx1, cy1, cx2, cy2, x2, y2
+ };
+ }
+
+ public boolean isCubic() {
+ return coordinates.length == 6;
+ }
+
+ public boolean isQuad() {
+ return coordinates.length == 4;
+ }
+
+ @Override
+ public Shape copy() {
+ return new Curve(this);
+ }
+
+ @Override
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof Curve ) {
+ Curve k = (Curve) shape;
+ coordinates = Arrays.copyOf(k.coordinates, k.coordinates.length);
+ }
+ }
+
+ @Override
+ public java.awt.Shape getShape() {
+ if( isCubic() ) {
+ return new CubicCurve2D.Double(
+ 0, 0,
+ coordinates[0] - x, coordinates[1] - y,
+ coordinates[2] - x, coordinates[3] - y,
+ coordinates[4] - x, coordinates[5] - y
+ );
+ } else {
+ return new QuadCurve2D.Double(
+ 0, 0,
+ coordinates[0] - x, coordinates[1] - y,
+ coordinates[2] - x, coordinates[3] - y
+ );
+ }
+ }
+
+ @Override
+ public void scale( double factor ) {
+ super.scale(factor);
+ coordinates[coordinates.length - 4] *= factor;
+ coordinates[coordinates.length - 3] *= factor;
+ coordinates[coordinates.length - 2] *= factor;
+ coordinates[coordinates.length - 1] *= factor;
+ }
+
+ @Override
+ public void move( double dx, double dy ) {
+ super.move(dx, dy);
+ for( int i = 0; i < coordinates.length; i += 2 ) {
+ coordinates[i] = coordinates[i] + dx;
+ coordinates[i + 1] = coordinates[i + 1] + dy;
+ }
+ }
+
+ @Override
+ public void moveTo( double x, double y ) {
+ double dx = x - x, dy = y - y;
+ move(dx, dy);
+ }
+
+ @Override
+ public boolean equals( Object o ) {
+ if( this == o ) return true;
+ if( o == null || getClass() != o.getClass() ) return false;
+ Curve pCurve = (Curve) o;
+ return super.equals(o) &&
+ getStart().equals(pCurve.getStart()) &&
+ getControl1().equals(pCurve.getControl1()) &&
+ getControl2().equals(pCurve.getControl2()) &&
+ getEnd().equals(pCurve.getEnd());
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getCanonicalName() + "[" +
+ "x=" + x +
+ ",y=" + y +
+ "x2=" + coordinates[coordinates.length - 2] +
+ ",y2=" + coordinates[coordinates.length - 1] +
+ ']';
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/CustomShape.java b/src/schule/ngb/zm/formen/CustomShape.java
new file mode 100644
index 0000000..229978c
--- /dev/null
+++ b/src/schule/ngb/zm/formen/CustomShape.java
@@ -0,0 +1,53 @@
+package schule.ngb.zm.formen;
+
+import java.awt.geom.Path2D;
+
+public class CustomShape extends Shape {
+
+ protected Path2D.Double path;
+
+ public CustomShape( double x, double y ) {
+ super(x, y);
+ path = new Path2D.Double();
+ }
+
+ public CustomShape( CustomShape custom ) {
+ super(custom.x, custom.y);
+ path = custom.path;
+ }
+
+ public void lineTo( double x, double y ) {
+ path.lineTo(x - x, y - y);
+ }
+
+ public void arcTo( double x1, double y1, double x2, double y2 ) {
+ path.quadTo(x1 - x, y1 - y, x2 - x, y2 - y);
+ }
+
+ public void curveTo( double x1, double y1, double x2, double y2, double x3, double y3 ) {
+ path.curveTo(x1 - x, y1 - y, x2 - x, y2 - y, x3 - x, y3 - y);
+ }
+
+ public void close() {
+ path.lineTo(0, 0);
+ }
+
+ @Override
+ public Shape copy() {
+ return new CustomShape(this);
+ }
+
+ @Override
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof CustomShape ) {
+ path = new Path2D.Double(path);
+ }
+ }
+
+ @Override
+ public java.awt.Shape getShape() {
+ return new Path2D.Double(path);
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/Drache.java b/src/schule/ngb/zm/formen/Drache.java
deleted file mode 100644
index 69415da..0000000
--- a/src/schule/ngb/zm/formen/Drache.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.Path2D;
-
-public class Drache extends Form {
-
- private double breite;
-
- private double hoehe;
-
- private double verhaeltnis;
-
- public Drache( double pX, double pY, double pBreite, double pHoehe ) {
- this(pX, pY, pBreite, pHoehe, 0.5);
- }
-
- public Drache( double pX, double pY, double pBreite, double pHoehe, double pVerhaeltnis ) {
- super(pX, pY);
- breite = pBreite;
- hoehe = pHoehe;
- verhaeltnis = pVerhaeltnis;
- setAnkerpunkt(ZENTRUM);
- }
-
- public Drache( Drache pDrache ) {
- this(pDrache.x, pDrache.y, pDrache.breite, pDrache.hoehe, pDrache.verhaeltnis);
- kopiere(pDrache);
- }
-
- public double getBreite() {
- return breite;
- }
-
- public void setBreite( double breite ) {
- this.breite = breite;
- }
-
- public double getHoehe() {
- return hoehe;
- }
-
- public void setHoehe( double hoehe ) {
- this.hoehe = hoehe;
- }
-
- public double getVerhaeltnis() {
- return verhaeltnis;
- }
-
- public void setVerhaeltnis( double pVerhaeltnis ) {
- this.verhaeltnis = pVerhaeltnis;
- }
-
- @Override
- public void kopiere( Form pForm ) {
- super.kopiere(pForm);
- if( pForm instanceof Drache ) {
- Drache d = (Drache) pForm;
- breite = d.breite;
- hoehe = d.hoehe;
- verhaeltnis = d.verhaeltnis;
- }
- }
-
- @Override
- public Drache kopie() {
- return new Drache(this);
- }
-
- @Override
- public void skalieren( double pFaktor ) {
- super.skalieren(pFaktor);
- breite *= pFaktor;
- hoehe *= pFaktor;
- }
-
- @Override
- public void setAnkerpunkt( byte pAnker ) {
- ankerBerechnen(breite, hoehe, pAnker);
- }
-
- @Override
- public Shape getShape() {
- double bHalb = breite * .5, hVerh = verhaeltnis*hoehe;
- Path2D shape = new Path2D.Double();
- shape.moveTo(bHalb, 0);
- shape.lineTo(breite, hVerh);
- shape.lineTo(bHalb, hoehe);
- shape.lineTo(0, hVerh);
- shape.closePath();
- return shape;
- }
-
- @Override
- public boolean equals( Object o ) {
- if( this == o ) return true;
- if( o == null || getClass() != o.getClass() ) return false;
- Drache d = (Drache) o;
- return super.equals(o) &&
- Double.compare(d.breite, breite) == 0 &&
- Double.compare(d.hoehe, hoehe) == 0 &&
- Double.compare(d.verhaeltnis, verhaeltnis) == 0;
- }
-
- @Override
- public String toString() {
- return getClass().getCanonicalName() + '[' +
- "breite=" + breite +
- ",hoehe=" + hoehe +
- ",verhaeltnis=" + verhaeltnis +
- ",x=" + x +
- ",y=" + y +
- ']';
- }
-
-}
diff --git a/src/schule/ngb/zm/formen/Dreieck.java b/src/schule/ngb/zm/formen/Dreieck.java
deleted file mode 100644
index e119003..0000000
--- a/src/schule/ngb/zm/formen/Dreieck.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.Point2D;
-import java.util.Arrays;
-
-public class Dreieck extends Vieleck {
-
- public Dreieck( double pX, double pY, Point2D... pEcken ) {
- super(pX, pY, Arrays.copyOf(pEcken, 3));
- if( pEcken.length < 3 ) {
- throw new IllegalArgumentException("Ein Dreieck muss genau drei Eckpunkte besitzen.");
- }
- }
-
- public Dreieck( Point2D... pEcken ) {
- super(Arrays.copyOf(pEcken, 3));
- if( pEcken.length < 3 ) {
- throw new IllegalArgumentException("Ein Dreieck muss genau drei Eckpunkte besitzen.");
- }
- }
-
- public Dreieck( Dreieck pDreieck ) {
- super(pDreieck.x, pDreieck.y);
- kopiere(pDreieck);
- }
-
- @Override
- public Form kopie() {
- return new Dreieck(this);
- }
-}
diff --git a/src/schule/ngb/zm/formen/Ellipse.java b/src/schule/ngb/zm/formen/Ellipse.java
index e0dd1e2..ae3a93e 100644
--- a/src/schule/ngb/zm/formen/Ellipse.java
+++ b/src/schule/ngb/zm/formen/Ellipse.java
@@ -1,73 +1,73 @@
package schule.ngb.zm.formen;
-import java.awt.*;
+import schule.ngb.zm.Options;
+
import java.awt.geom.Ellipse2D;
-public class Ellipse extends Form {
+public class Ellipse extends Shape {
- private double breite;
+ protected double width;
- private double hoehe;
+ protected double height;
- public Ellipse( double pX, double pY, double pBreite, double pHoehe ) {
- super(pX, pY);
- breite = pBreite;
- hoehe = pHoehe;
- setAnkerpunkt(ZENTRUM);
+ public Ellipse( double x, double y, double width, double height ) {
+ super(x, y);
+ this.width = width;
+ this.height = height;
+ setAnchor(CENTER);
}
- public Ellipse( Ellipse pEllipse ) {
- this(pEllipse.x, pEllipse.y, pEllipse.breite, pEllipse.hoehe);
- kopiere(pEllipse);
+ public Ellipse( Ellipse ellipse ) {
+ this(ellipse.x, ellipse.y, ellipse.width, ellipse.height);
+ copyFrom(ellipse);
}
- public double getBreite() {
- return breite;
+ public double getWidth() {
+ return width;
}
- public void setBreite( double breite ) {
- this.breite = breite;
+ public void setWidth( double width ) {
+ this.width = width;
}
- public double getHoehe() {
- return hoehe;
+ public double getHeight() {
+ return height;
}
- public void setHoehe( double hoehe ) {
- this.hoehe = hoehe;
+ public void setHeight( double height ) {
+ this.height = height;
}
@Override
- public void kopiere( Form pForm ) {
- super.kopiere(pForm);
- if( pForm instanceof Ellipse ) {
- Ellipse e = (Ellipse) pForm;
- breite = e.breite;
- hoehe = e.hoehe;
+ public void copyFrom( Shape shape ) {
+ super.copyFrom(shape);
+ if( shape instanceof Ellipse ) {
+ Ellipse e = (Ellipse) shape;
+ this.width = e.width;
+ this.height = e.height;
}
}
@Override
- public Ellipse kopie() {
+ public Ellipse copy() {
return new Ellipse(this);
}
@Override
- public void skalieren( double pFaktor ) {
- super.skalieren(pFaktor);
- breite *= pFaktor;
- hoehe *= pFaktor;
+ public void scale( double factor ) {
+ super.scale(factor);
+ width *= factor;
+ height *= factor;
}
@Override
- public void setAnkerpunkt( byte pAnker ) {
- ankerBerechnen(breite, hoehe, pAnker);
+ public void setAnchor( Options.Direction anchor ) {
+ calculateAnchor(width, height, anchor);
}
@Override
- public Shape getShape() {
- Shape shape = new Ellipse2D.Double(0, 0, breite, hoehe);
- return shape;
+ public java.awt.Shape getShape() {
+ return new Ellipse2D.Double(0, 0, width, height);
}
@Override
@@ -76,15 +76,15 @@ public class Ellipse extends Form {
if( o == null || getClass() != o.getClass() ) return false;
Ellipse ellipse = (Ellipse) o;
return super.equals(o) &&
- Double.compare(ellipse.breite, breite) == 0 &&
- Double.compare(ellipse.hoehe, hoehe) == 0;
+ Double.compare(ellipse.width, width) == 0 &&
+ Double.compare(ellipse.height, height) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + '[' +
- "breite=" + breite +
- ",hoehe=" + hoehe +
+ "width=" + width +
+ ",height=" + height +
",x=" + x +
",y=" + y +
']';
diff --git a/src/schule/ngb/zm/formen/FilledShape.java b/src/schule/ngb/zm/formen/FilledShape.java
new file mode 100644
index 0000000..36df1a5
--- /dev/null
+++ b/src/schule/ngb/zm/formen/FilledShape.java
@@ -0,0 +1,41 @@
+package schule.ngb.zm.formen;
+
+import schule.ngb.zm.Color;
+
+public abstract class FilledShape extends StrokedShape {
+
+ protected Color fillColor = STD_FILLCOLOR;
+
+ public Color getFillColor() {
+ return fillColor;
+ }
+
+ public void setFillColor( Color color ) {
+ fillColor = color;
+ }
+
+ public void setFillColor( int gray ) {
+ setFillColor(gray, gray, gray, 255);
+ }
+
+ public void noFill() {
+ fillColor = null;
+ }
+
+ public void setFillColor( int gray, int alpha ) {
+ setFillColor(gray, gray, gray, alpha);
+ }
+
+ public void setFillColor( int red, int green, int blue ) {
+ setFillColor(red, green, blue, 255);
+ }
+
+ public void setFillColor( int red, int green, int blue, int alpha ) {
+ setFillColor(new Color(red, green, blue, alpha));
+ }
+
+ public void resetFill() {
+ setFillColor(STD_FILLCOLOR);
+ }
+
+}
diff --git a/src/schule/ngb/zm/formen/Form.java b/src/schule/ngb/zm/formen/Form.java
deleted file mode 100644
index 31284e8..0000000
--- a/src/schule/ngb/zm/formen/Form.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-
-public abstract class Form extends Fuellform {
-
-
- protected double x;
-
- protected double y;
-
- protected double drehwinkel = 0.0;
-
- protected double skalierung = 1.0;
-
- protected boolean sichtbar = true;
-
- protected Point2D.Double anker = new Point2D.Double();
-
- FormGruppe gruppe = null;
-
- public Form( double pX, double pY ) {
- x = pX;
- y = pY;
- }
-
- public Form() {
- this(0.0, 0.0);
- }
-
- public double getX() {
- return x;
- }
-
- public void setX( double x ) {
- this.x = x;
- }
-
- public double getY() {
- return y;
- }
-
- public void setY( double y ) {
- this.y = y;
- }
-
- public double getDrehwinkel() {
- return drehwinkel;
- }
-
- public double getSkalierung() {
- return skalierung;
- }
-
- public boolean istSichtbar() {
- return sichtbar;
- }
-
- public void verstecken() {
- sichtbar = false;
- }
-
- public void zeigen() {
- sichtbar = true;
- }
-
- public void umschalten() {
- sichtbar = !sichtbar;
- }
-
- public Point2D.Double getAnkerpunkt() {
- return new Point2D.Double(anker.x, anker.y);
- }
-
- public void setAnkerpunkt( byte pAnker ) {
- Shape shape = getShape();
- if( shape != null ) {
- Rectangle2D bounds = shape.getBounds2D();
- ankerBerechnen(bounds.getWidth(), bounds.getHeight(), pAnker);
- } else {
- anker.x = 0;
- anker.y = 0;
- }
- }
-
- public void setAnkerpunkt( Point2D.Double pAnker ) {
- anker.x = pAnker.x;
- anker.y = pAnker.y;
- }
-
- protected void ankerBerechnen( double pBreite, double pHoehe, byte pAnker ) {
- double bHalb = pBreite * .5, hHalb = pHoehe * .5;
- // pAnker == CENTER
- anker.x = bHalb;
- anker.y = hHalb;
- if( (pAnker & NORDEN) == NORDEN ) {
- anker.y -= hHalb;
- }
- if( (pAnker & SUEDEN) == SUEDEN ) {
- anker.y += hHalb;
- }
- if( (pAnker & WESTEN) == WESTEN ) {
- anker.x -= bHalb;
- }
- if( (pAnker & OSTEN) == OSTEN ) {
- anker.x += bHalb;
- }
- }
-
- public void kopiere( Form pForm ) {
- verschiebeNach(pForm);
- setFuellfarbe(pForm.getFuellfarbe());
- setKonturFarbe(pForm.getKonturFarbe());
- setKonturDicke(pForm.getKonturDicke());
- setKonturArt(pForm.getKonturArt());
- sichtbar = pForm.istSichtbar();
- drehwinkel = pForm.drehwinkel;
- skalieren(pForm.skalierung);
- setAnkerpunkt(pForm.getAnkerpunkt());
- }
-
- public abstract Form kopie();
-
- public Rechteck getBegrenzung() {
- return new Rechteck(this);
- }
-
- public void verschieben( double dx, double dy ) {
- x += dx;
- y += dy;
- }
-
- public void verschiebeNach( double pX, double pY ) {
- x = pX;
- y = pY;
- }
-
- public void verschiebeNach( Form pForm ) {
- verschiebeNach(pForm.x, pForm.y);
- }
-
- public void skalieren( double pFaktor ) {
- skalierung = pFaktor;
- anker.x *= pFaktor;
- anker.y *= pFaktor;
- }
-
- public void skalierenUm( double pFaktor ) {
- skalieren(skalierung * pFaktor);
- }
-
- public void drehen( double pWinkel ) {
- drehwinkel += pWinkel % 360;
- }
-
- public void drehenNach( double pWinkel ) {
- drehwinkel = pWinkel % 360;
- }
-
- /*public void scheren( double dx, double dy ) {
- verzerrung.shear(dx, dy);
- }*/
-
- public AffineTransform getVerzerrung() {
- AffineTransform verzerrung = new AffineTransform();
- verzerrung.translate(x, y);
- verzerrung.rotate(Math.toRadians(drehwinkel));
- //verzerrung.scale(skalierung, skalierung);
- verzerrung.translate(-anker.x, -anker.y);
- return verzerrung;
- }
-
- public final void zeichnen( Graphics2D graphics ) {
- zeichnen(graphics, getVerzerrung());
- }
-
- /**
- * Zeichnet die Form, aber wendet zuvor noch eine zusätzliche Transformations-
- * matrix an. Wird u.A. von der {@link FormGruppe} verwendet.
- * @param graphics
- * @param pVerzerrung
- */
- public void zeichnen( Graphics2D graphics, AffineTransform pVerzerrung ) {
- if( !sichtbar ) {
- return;
- }
-
- Shape shape = getShape();
- if( shape != null ) {
- if( pVerzerrung != null ) {
- shape = pVerzerrung.createTransformedShape(shape);
- }
-
- Color currentColor = graphics.getColor();
- if( fuellFarbe != null && fuellFarbe.getAlpha() > 0 ) {
- graphics.setColor(fuellFarbe);
- graphics.fill(shape);
- }
- if( konturFarbe != null && konturFarbe.getAlpha() > 0
- && konturDicke > 0.0 ) {
- graphics.setColor(konturFarbe);
- graphics.setStroke(createStroke());
- graphics.draw(shape);
- }
- graphics.setColor(currentColor);
- }
- }
-
- public abstract Shape getShape();
-
- @Override
- public boolean equals( Object o ) {
- if( this == o ) return true;
- if( o == null || getClass() != o.getClass() ) return false;
- Form form = (Form) o;
- return Double.compare(form.x, x) == 0 &&
- Double.compare(form.y, y) == 0 &&
- Double.compare(form.drehwinkel, drehwinkel) == 0 &&
- Double.compare(form.skalierung, skalierung) == 0;
- }
-
-}
diff --git a/src/schule/ngb/zm/formen/FormGruppe.java b/src/schule/ngb/zm/formen/FormGruppe.java
deleted file mode 100644
index 437dc45..0000000
--- a/src/schule/ngb/zm/formen/FormGruppe.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package schule.ngb.zm.formen;
-
-import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.util.ArrayList;
-import java.util.List;
-
-public class FormGruppe extends Form {
-
- private List