Merge branch 'main' into turtle

This commit is contained in:
ngb 2021-12-30 18:07:47 +01:00
commit 271b65bce1
75 changed files with 5832 additions and 3446 deletions

View File

@ -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()));
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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 <code>true</code>, wenn das Objekt sichtbar ist.
*/
public boolean istSichtbar();
boolean isVisible();
/**
* Wird aufgerufen, um das Objekt auf die Zeichenfläche <var>graphics</var>
* zu zeichnen.
* zu draw.
* <p>
* 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 );
}

View File

@ -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<AffineTransform> 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());
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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<Ebene> ebenen;
public Leinwand( int pBreite, int pHoehe ) {
Dimension dim = new Dimension(pBreite, pHoehe);
super.setSize(pBreite, pHoehe);
this.setPreferredSize(dim);
this.setMinimumSize(dim);
ebenen = new LinkedList<>();
ebenen.add(new Zeichenebene());
ebenen.add(new Formenebene());
setBackground(Konstanten.STD_HINTERGRUND);
}
@Override
public void setSize( int pBreite, int pHoehe ) {
Dimension dim = new Dimension(pBreite, pHoehe);
super.setSize(pBreite, pHoehe);
this.setPreferredSize(dim);
this.setMinimumSize(dim);
for( Ebene ebene : ebenen ) {
ebene.setGroesse(getWidth(), getHeight());
}
}
public void hinzu( Ebene pEbene ) {
if( pEbene != null ) {
pEbene.setGroesse(getWidth(), getHeight());
ebenen.add(pEbene);
}
}
public void hinzu( int pIndex, Ebene pEbene ) {
if( pEbene != null ) {
pEbene.setGroesse(getWidth(), getHeight());
ebenen.add(pIndex, pEbene);
}
}
public java.util.List<Ebene> getEbenen() {
return ebenen;
}
/**
* Holt die {@link Ebene} am Index <var>i</var> (beginnend bei <code>0</code>).
*
* @param i Index der Ebene (beginnend bei <code>0</code>).
* @return Die Ebene am Index <var>i</var> oder <code>null</code>.
* @throws IndexOutOfBoundsException Falls der Index nicht existiert.
*/
public Ebene getEbene( int i ) {
if( ebenen.size() > i ) {
return ebenen.get(i);
} else {
throw new IndexOutOfBoundsException("Keine Ebene mit dem Index " + i + " vorhanden (maximum: " + (ebenen.size() - 1) + ").");
}
}
/**
* Holt die erste Ebene des angegebenen Typs aus der Liste der Ebenen.
* Existiert keine solche Ebene, wird <code>null</code> zurückgegeben.
*
* @param pClazz Typ der Ebene.
* @param <L>
* @return Erste Ebene vom angegeben Typ.
*/
public <L extends Ebene> L getEbene( Class<L> pClazz ) {
for( Ebene ebene : ebenen ) {
if( ebene.getClass().equals(pClazz) ) {
return pClazz.cast(ebene);
}
}
return null;
}
public <L extends Ebene> java.util.List<L> getEbenen( Class<L> pClazz ) {
ArrayList<L> result = new ArrayList<>(ebenen.size());
for( Ebene ebene : ebenen ) {
if( ebene.getClass().equals(pClazz) ) {
result.add(pClazz.cast(ebene));
}
}
return result;
}
public void paintComponent( Graphics g ) {
Graphics2D g2d = (Graphics2D) g.create();
for( Ebene ebene : ebenen ) {
ebene.zeichnen(g2d);
}
g2d.dispose();
}
}

View File

@ -0,0 +1,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;
}
}
}

View File

@ -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<java.awt.Shape> shapes;
private boolean instantDraw = false;
public Shape2DLayer() {
super();
shapes = new LinkedList<java.awt.Shape>();
}
public Shape2DLayer( boolean instantDraw ) {
super();
shapes = new LinkedList<java.awt.Shape>();
this.instantDraw = instantDraw;
}
public Shape2DLayer( int width, int height ) {
super(width, height);
shapes = new LinkedList<java.awt.Shape>();
}
public Shape2DLayer( int width, int height, boolean instantDraw ) {
super(width, height);
shapes = new LinkedList<java.awt.Shape>();
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<java.awt.Shape> 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);
}
}

View File

@ -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 <code>true</code>, wenn das Objekt aktiv ist.
*/
public boolean istAktiv();
public boolean isActive();
/**
* Änderung des Zustandes des Objekts abhängig vom Zeitintervall
* <var>delta</var> in Sekunden.
* @param delta Zeitintervall seit dem letzten Aufruf (in Sekunden).
*/
public void aktualisieren( double delta );
public void update( double delta );
}

View File

@ -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 + "]";
}
}

View File

@ -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 + "}";
}
}

View File

@ -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<AffineTransform> transformStack = new Stack<>();
public Zeichenebene() {
super();
transformStack.push(new AffineTransform());
strokeColor = Color.BLACK;
fillColor = Color.WHITE;
strokeWeight = 1.0;
}
public Zeichenebene( int pWidth, int pHeight) {
super(pWidth, pHeight);
}
public void setAnchor( int pAnchor ) {
default_anchor = pAnchor;
}
public void leeren() {
clear(200);
}
public void clear(int gray) {
clear(gray, gray, gray, 255);
}
public void clear(int gray, int alpha) {
clear(gray, gray, gray, alpha);
}
public void clear(int red, int green, int blue) {
clear(red, green, blue, 255);
}
public void clear(int red, int green, int blue, int alpha) {
clear(new Color(red, green, blue, alpha));
}
public void clear(Color pColor) {
/*graphics.setBackground(pColor);
graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());*/
Color currentColor = zeichnung.getColor();
pushMatrix();
resetMatrix();
zeichnung.setColor(pColor);
zeichnung.fillRect(0, 0, puffer.getWidth(), puffer.getHeight());
zeichnung.setColor(currentColor);
popMatrix();
}
public void line(double x1, double y1, double x2, double y2) {
Shape line = new Line2D.Double(x1, y1, x2, y2);
//line = transformToCanvas(line);
drawShape(line);
}
public void pixel(double x, double y) {
square(x, y, 1);
}
public void square(double x, double y, double w) {
rect(x, y, w, w);
}
public void square(double x, double y, double w, int anchor) {
rect(x, y, w, w, anchor);
}
public void rect(double x, double y, double w, double h) {
rect(x, y, w, h, default_anchor);
}
public void rect(double x, double y, double w, double h, int anchor) {
Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
Shape rect = new Rectangle2D.Double(
anchorPoint.getX(), anchorPoint.getY(), w, h
);
//rect = transformToCanvas(rect);
fillShape(rect);
drawShape(rect);
}
public void point(double x, double y) {
circle(x - 1, y - 1, 2);
}
public void circle(double x, double y, double d) {
ellipse(x, y, d, d, default_anchor);
}
public void circle(double x, double y, double d, int anchor) {
ellipse(x, y, d, d, anchor);
}
public void ellipse(double x, double y, double w, double h) {
ellipse(x, y, w, h, default_anchor);
}
public void ellipse(double x, double y, double w, double h, int anchor) {
Point2D.Double anchorPoint = getAnchorPoint(x, y, w, h, anchor);
Shape ellipse = new Ellipse2D.Double(
anchorPoint.x, anchorPoint.y, w, h
);
//ellipse = transformToCanvas(ellipse);
fillShape(ellipse);
drawShape(ellipse);
}
public void arc( double x, double y, double d, double angle1, double angle2 ) {
while (angle2 < angle1) angle2 += 360.0;
Point2D.Double anchorPoint = getAnchorPoint(x, y, d, d, ZENTRUM);
Shape arc = new Arc2D.Double(
anchorPoint.x,
anchorPoint.y,
d, d,
angle1, angle2 - angle1,
Arc2D.OPEN
);
//arc = transformToCanvas(arc);
drawShape(arc);
}
public void pie( double x, double y, double d, double angle1, double angle2 ) {
while (angle2 < angle1) angle2 += 360.0;
Point2D.Double anchorPoint = getAnchorPoint(x, y, d, d, ZENTRUM);
Shape arc = new Arc2D.Double(
anchorPoint.x,
anchorPoint.y,
d, d,
angle1, angle2 - angle1,
Arc2D.PIE
);
//arc = transformToCanvas(arc);
fillShape(arc);
drawShape(arc);
}
private Point2D.Double transformToCanvas(double x, double y) {
return transformToCanvas(new Point2D.Double(x, y));
}
private Point2D.Double transformToCanvas( Point2D.Double pPoint ) {
AffineTransform matrix = getMatrix();
matrix.transform(pPoint, pPoint);
return pPoint;
}
private Shape transformToCanvas( Shape pShape ) {
AffineTransform matrix = getMatrix();
return matrix.createTransformedShape(pShape);
}
private Point2D.Double transformToUser(double x, double y) {
return transformToUser(new Point2D.Double(x, y));
}
private Point2D.Double transformToUser( Point2D.Double pPoint ) {
AffineTransform matrix = getMatrix();
try {
matrix.inverseTransform(pPoint, pPoint);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return pPoint;
}
private Shape transformToUser( Shape pShape ) {
AffineTransform matrix = getMatrix();
try {
matrix = matrix.createInverse();
pShape = matrix.createTransformedShape(pShape);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return pShape;
}
private AffineTransform getAnchorTransform( Shape pShape, int anchor ) {
AffineTransform at = new AffineTransform();
Rectangle2D bounds = pShape.getBounds2D();
switch(anchor) {
case ZENTRUM:
at.translate(
bounds.getWidth() / -2.0,
bounds.getHeight() / -2.0
);
break;
case WESTEN:
at.translate(
0, bounds.getHeight() / -2.0
);
break;
case SUEDWESTEN:
at.translate(
0, -1.0 * bounds.getHeight()
);
break;
}
return at;
}
private Point2D.Double getAnchorPoint(double x, double y, double w, double h, int anchor) {
switch(anchor) {
case ZENTRUM:
x -= w / 2.0;
y -= h / 2.0;
break;
case WESTEN:
y -= h / 2.0;
break;
case SUEDWESTEN:
y -= h;
break;
}
return new Point2D.Double(x, y);
}
private Point2D.Double getAnchorPoint(Shape pShape, int anchor) {
Rectangle2D bounds = pShape.getBounds2D();
return getAnchorPoint(
bounds.getX(), bounds.getY(),
bounds.getWidth(), bounds.getHeight(), anchor
);
}
private void fillShape( Shape pShape ) {
if (fillColor != null && fillColor.getAlpha() > 0.0) {
zeichnung.setColor(fillColor);
zeichnung.fill(pShape);
}
}
private void drawShape( Shape pShape ) {
if (strokeColor != null && strokeColor.getAlpha() > 0.0
&& strokeWeight > 0.0 ) {
zeichnung.setColor(strokeColor);
zeichnung.draw(pShape);
}
}
public void translate( double dx, double dy ) {
zeichnung.translate(dx, dy);
}
public void scale( double factor ) {
zeichnung.scale(factor, factor);
}
public void rotate( double pAngle ) {
zeichnung.rotate(Math.toRadians(pAngle));
}
public void shear( double dx, double dy ) {
zeichnung.shear(dx, dy);
}
public AffineTransform getMatrix() {
return zeichnung.getTransform();
}
public void pushMatrix() {
transformStack.push(zeichnung.getTransform());
}
public void popMatrix() {
if( transformStack.isEmpty() ) {
resetMatrix();
} else {
zeichnung.setTransform(transformStack.pop());
}
}
public void resetMatrix() {
zeichnung.setTransform(new AffineTransform());
}
}

View File

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

View File

@ -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<Layer> 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 <code>0</code>.
* @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<Layer> getLayers() {
return layers;
}
/**
* Holt die Ebene am Index <var>i</var> (beginnend bei <code>0</code>).
*
* @param i Index der Ebene (beginnend bei <code>0</code>).
* @return Die Ebene am Index <var>i</var> oder <code>null</code>.
* @throws IndexOutOfBoundsException Falls der Index nicht existiert.
*/
public 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 <code>null</code> zurückgegeben.
*
* @param clazz Typ der Ebene.
* @param <L>
* @return Erste Ebene vom angegeben Typ.
*/
public <L extends Layer> L getLayer( Class<L> 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 <L>
* @return
*/
public <L extends Layer> java.util.List<L> getLayers( Class<L> pClazz ) {
ArrayList<L> 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();
*/
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 +
']';
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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 +
']';
}
}

View File

@ -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] +
']';
}
}

View File

@ -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);
}
}

View File

@ -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 +
']';
}
}

View File

@ -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);
}
}

View File

@ -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 +
']';

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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<Form> formen;
public FormGruppe() {
super();
formen = new ArrayList<>(10);
}
public FormGruppe( double pX, double pY ) {
super(pX, pY);
formen = new ArrayList<>(10);
}
public FormGruppe( double pX, double pY, Form... pFormen ) {
super(pX, pY);
formen = new ArrayList<>(pFormen.length);
for( Form form : pFormen ) {
formen.add(form);
form.gruppe = this;
}
setAnkerpunkt(ZENTRUM);
}
public Form kopie() {
return null;
}
public void hinzu( Form... pFormen ) {
for( Form form : pFormen ) {
hinzu(form, false);
}
}
public void hinzu( Form pForm ) {
hinzu(pForm, false);
}
public void hinzu( Form pForm, boolean pKoordinatenAnpassen ) {
if( pKoordinatenAnpassen ) {
pForm.x = pForm.x - x;
pForm.y = pForm.y - y;
}
formen.add(pForm);
pForm.gruppe = this;
}
@Override
public void setAnkerpunkt( byte pAnker ) {
double minx = Double.MAX_VALUE, miny = Double.MAX_VALUE,
maxx = Double.MIN_VALUE, maxy = Double.MIN_VALUE;
for( Form form : formen ) {
Rechteck bounds = form.getBegrenzung();
if( bounds.x < minx )
minx = bounds.x;
if( bounds.y < miny )
miny = bounds.y;
if( bounds.x+bounds.breite > maxx )
maxx = bounds.x+bounds.breite;
if( bounds.y+bounds.hoehe > maxy )
maxy = bounds.y+bounds.hoehe;
}
ankerBerechnen(maxx-minx, maxy-miny, pAnker);
}
@Override
public Shape getShape() {
Path2D.Double gruppe = new Path2D.Double();
for( Form form : formen ) {
gruppe.append(form.getShape(), false);
}
return gruppe;
}
@Override
public void zeichnen( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !sichtbar ) {
return;
}
AffineTransform verzerrung = new AffineTransform();
verzerrung.translate(x, y);
verzerrung.rotate(Math.toRadians(drehwinkel));
//verzerrung.scale(skalierung, skalierung);
verzerrung.translate(-anker.x, -anker.y);
for( Form f: formen ) {
AffineTransform af = f.getVerzerrung();
af.preConcatenate(verzerrung);
f.zeichnen(graphics, af);
}
}
}

View File

@ -1,70 +0,0 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Ebene;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
public class Formenebene extends Ebene {
private LinkedList<Form> formen;
public Formenebene() {
super();
formen = new LinkedList<Form>();
}
public Formenebene( int pWidth, int pHeight ) {
super(pWidth, pHeight);
formen = new LinkedList<Form>();
}
public void anzeigen( Form... pFormen ) {
synchronized( formen ) {
for( Form f: pFormen ) {
formen.add(f);
}
}
}
public void alleVerstecken() {
synchronized( formen ) {
for( Form form : formen ) {
form.verstecken();
}
}
}
public void alleZeigen() {
synchronized( formen ) {
for( Form form : formen ) {
form.zeigen();
}
}
}
public void leeren() {
Color currentColor = zeichnung.getBackground();
zeichnung.setBackground(new Color(0, 0, 0, 0));
zeichnung.clearRect(0, 0, puffer.getWidth(), puffer.getHeight());
zeichnung.setBackground(currentColor);
}
public java.util.List<Form> getShapes() {
return formen;
}
@Override
public void zeichnen( Graphics2D pGraphics ) {
synchronized( formen ) {
for( Form form : formen ) {
if( form.istSichtbar() ) {
form.zeichnen(zeichnung);
}
}
}
super.zeichnen(pGraphics);
}
}

View File

@ -1,40 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Path2D;
public class Freiform extends Form {
private Path2D.Double pfad;
public Freiform(double pX, double pY) {
super(pX, pY);
pfad = new Path2D.Double();
}
public void linieNach( double pX, double pY ) {
pfad.lineTo(pX-x, pY-y);
}
public void bogenNach( double pX1, double pY1, double pX2, double pY2 ) {
pfad.quadTo(pX1-x, pY1-y, pX2-x, pY2-y);
}
public void kurveNach( double pX1, double pY1, double pX2, double pY2, double pX3, double pY3 ) {
pfad.curveTo(pX1-x, pY1-y, pX2-x, pY2-y, pX3-x, pY3-y);
}
public void schliessen() {
pfad.lineTo(0,0);
}
@Override
public Form kopie() {
return null;
}
@Override
public Shape getShape() {
return new Path2D.Double(pfad);
}
}

View File

@ -1,49 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
public abstract class Fuellform extends Konturform {
public static final Color STD_FUELLFARBE = Color.WHITE;
protected Color fuellFarbe = STD_FUELLFARBE;
public Color getFuellfarbe() {
return fuellFarbe;
}
public void setFuellfarbe( Color pFuellFarbe) {
fuellFarbe = pFuellFarbe;
}
public void keineFuellung() {
fuellFarbe = null;
}
public void setFuellfarbe( int gray) {
setFuellfarbe(gray, gray, gray, 255);
}
public void setFuellfarbe( int gray, int alpha) {
setFuellfarbe(gray, gray, gray, alpha);
}
public void setFuellfarbe( int red, int green, int blue) {
setFuellfarbe(red, green, blue, 255);
}
public void setFuellfarbe( 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");
setFuellfarbe(new Color(red, green, blue, alpha));
}
}

View File

@ -0,0 +1,118 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.geom.Path2D;
public class Kite extends Shape {
protected double width;
protected double height;
protected double ratio;
public Kite( double x, double y, double width, double height ) {
this(x, y, width, height, 0.5);
}
public Kite( double x, double y, double width, double height, double ratio ) {
super(x, y);
this.width = width;
this.height = height;
this.ratio = ratio;
setAnchor(CENTER);
}
public Kite( Kite pKite ) {
this(pKite.x, pKite.y, pKite.width, pKite.height, pKite.ratio);
copyFrom(pKite);
}
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 getRatio() {
return ratio;
}
public void setRatio( double ratio ) {
this.ratio = ratio;
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Kite ) {
Kite d = (Kite) shape;
width = d.width;
height = d.height;
ratio = d.ratio;
}
}
@Override
public Kite copy() {
return new Kite(this);
}
@Override
public void scale( double factor ) {
super.scale(factor);
width *= factor;
height *= factor;
}
@Override
public void setAnchor( Options.Direction anchor ) {
calculateAnchor(width, height, anchor);
}
@Override
public java.awt.Shape getShape() {
double hHalf = width * .5, hRatio = ratio * height;
Path2D shape = new Path2D.Double();
shape.moveTo(hHalf, 0);
shape.lineTo(width, hRatio);
shape.lineTo(hHalf, height);
shape.lineTo(0, hRatio);
shape.closePath();
return shape;
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Kite d = (Kite) o;
return super.equals(o) &&
Double.compare(d.width, width) == 0 &&
Double.compare(d.height, height) == 0 &&
Double.compare(d.ratio, ratio) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + '[' +
"width=" + width +
",height=" + height +
",verhaeltnis=" + ratio +
",x=" + x +
",y=" + y +
']';
}
}

View File

@ -1,114 +0,0 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Konstanten;
import schule.ngb.zm.Zeichenbar;
import java.awt.*;
public abstract class Konturform extends Konstanten implements Zeichenbar {
public static final int DURCHGEZOGEN = 16;
public static final int GESTRICHELT = 17;
public static final int GEPUNKTET = 18;
public static final Color STD_KONTURFABRE = Color.BLACK;
public static final double STD_KONTURDICKE = 1.0;
protected Color konturFarbe = STD_KONTURFABRE;
protected double konturDicke = STD_KONTURDICKE;
protected int konturArt = DURCHGEZOGEN;
public Color getKonturFarbe() {
return konturFarbe;
}
public void setKonturFarbe(Color pKonturFarbe) {
this.konturFarbe = pKonturFarbe;
}
public void keineKontur() {
konturFarbe = null;
}
public void setKonturFarbe(int gray) {
setKonturFarbe(gray, gray, gray, 255);
}
public void setKonturFarbe(int gray, int alpha) {
setKonturFarbe(gray, gray, gray, alpha);
}
public void setKonturFarbe(int red, int green, int blue) {
setKonturFarbe(red, green, blue, 255);
}
public void setKonturFarbe(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");
setKonturFarbe(new Color(red, green, blue, alpha));
}
public double getKonturDicke() {
return konturDicke;
}
public void setKonturDicke(double pKonturDicke) {
this.konturDicke = pKonturDicke;
}
public int getKonturArt() {
return konturArt;
}
public void setKonturArt(int konturArt) {
switch (konturArt) {
case GESTRICHELT:
this.konturArt = GESTRICHELT;
break;
case GEPUNKTET:
this.konturArt = GEPUNKTET;
break;
default:
this.konturArt = DURCHGEZOGEN;
break;
}
}
public abstract void zeichnen(Graphics2D graphics);
protected Stroke createStroke() {
switch(konturArt) {
case GEPUNKTET:
return new BasicStroke(
(float) konturDicke,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
10.0f, new float[]{1.0f,5.0f}, 0.0f);
case GESTRICHELT:
return new BasicStroke(
(float) konturDicke,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
10.0f, new float[]{5.0f}, 0.0f);
case DURCHGEZOGEN:
default:
return new BasicStroke(
(float) konturDicke,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
}
}
}

View File

@ -1,67 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class Kreis extends Form {
public double radius;
public Kreis( double pX, double pY, double pRadius ) {
super(pX, pY);
radius = pRadius;
setAnkerpunkt(ZENTRUM);
}
public Kreis( Kreis pKreis ) {
this(pKreis.x, pKreis.y, pKreis.radius);
kopiere(pKreis);
}
@Override
public void skalieren( double pFaktor ) {
super.skalieren(pFaktor);
radius *= pFaktor;
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Kreis ) {
radius = ((Kreis) pForm).radius;
}
}
@Override
public Kreis kopie() {
return new Kreis(this);
}
@Override
public Shape getShape() {
return new Ellipse2D.Double(0, 0, radius * 2.0, radius * 2.0);
}
@Override
public void setAnkerpunkt( byte pAnker ) {
ankerBerechnen(radius + radius, radius + radius, pAnker);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Kreis kreis = (Kreis) o;
return super.equals(o) && Double.compare(kreis.radius, radius) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x=" + x +
",y=" + y +
",radius=" + radius +
']';
}
}

View File

@ -1,183 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.util.Arrays;
public class Kurve extends Form {
private double[] koordinaten;
public Kurve( double pX, double pY, double pCx, double pCy, double pX2, double pY2 ) {
super(pX, pY);
koordinaten = new double[]{
pCx, pCy, pX2, pY2
};
keineFuellung();
}
public Kurve( double pX, double pY, double pCx1, double pCy1, double pCx2, double pCy2, double pX2, double pY2 ) {
super(pX, pY);
koordinaten = new double[]{
pCx1, pCy1, pCx2, pCy2, pX2, pY2
};
keineFuellung();
}
public Kurve( Kurve pKurve ) {
super(pKurve.x, pKurve.y);
koordinaten = Arrays.copyOf(pKurve.koordinaten, pKurve.koordinaten.length);
}
public Point2D getStartpunkt() {
return new Point2D.Double(x, y);
}
public void setStartpunkt( double pX, double pY ) {
x = pX;
y = pY;
}
public Point2D getEndpunkt() {
return new Point2D.Double(
koordinaten[koordinaten.length - 2],
koordinaten[koordinaten.length - 1]
);
}
public void setEndpunkt( double pX, double pY ) {
koordinaten[koordinaten.length - 2] = pX;
koordinaten[koordinaten.length - 1] = pY;
}
public Point2D getKontrollpunkt1() {
return new Point2D.Double(
koordinaten[0],
koordinaten[1]
);
}
public void setKontrollpunkt1( double pX, double pY ) {
koordinaten[0] = pX;
koordinaten[1] = pY;
}
public Point2D getKontrollpunkt2() {
return new Point2D.Double(
koordinaten[koordinaten.length - 4],
koordinaten[koordinaten.length - 3]
);
}
public void setKontrollpunkt2( double pX, double pY ) {
koordinaten[koordinaten.length - 4] = pX;
koordinaten[koordinaten.length - 3] = pY;
}
public void setPunkte( double pX, double pY, double pCx, double pCy, double pX2, double pY2 ) {
setStartpunkt(pX, pY);
koordinaten = koordinaten = new double[]{
pCx, pCy, pX2, pY2
};
}
public void setPunkte( double pX, double pY, double pCx1, double pCy1, double pCx2, double pCy2, double pX2, double pY2 ) {
setStartpunkt(pX, pY);
koordinaten = new double[]{
pCx1, pCy1, pCx2, pCy2, pX2, pY2
};
}
public boolean istKubisch() {
return koordinaten.length == 6;
}
public boolean istQuadratisch() {
return koordinaten.length == 4;
}
@Override
public Form kopie() {
return new Kurve(this);
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Kurve ) {
Kurve k = (Kurve) pForm;
koordinaten = Arrays.copyOf(k.koordinaten, k.koordinaten.length);
}
}
@Override
public Shape getShape() {
if( istKubisch() ) {
return new CubicCurve2D.Double(
0, 0,
koordinaten[0] - x, koordinaten[1] - y,
koordinaten[2] - x, koordinaten[3] - y,
koordinaten[4] - x, koordinaten[5] - y
);
} else {
return new QuadCurve2D.Double(
0, 0,
koordinaten[0] - x, koordinaten[1] - y,
koordinaten[2] - x, koordinaten[3] - y
);
}
}
@Override
public void skalieren( double pFaktor ) {
super.skalieren(pFaktor);
koordinaten[koordinaten.length - 4] *= pFaktor;
koordinaten[koordinaten.length - 3] *= pFaktor;
koordinaten[koordinaten.length - 2] *= pFaktor;
koordinaten[koordinaten.length - 1] *= pFaktor;
}
@Override
public void verschieben( double dx, double dy ) {
super.verschieben(dx, dy);
for( int i = 0; i < koordinaten.length; i += 2 ) {
koordinaten[i] = koordinaten[i] + dx;
koordinaten[i + 1] = koordinaten[i + 1] + dy;
}
}
@Override
public void verschiebeNach( double pX, double pY ) {
double dx = pX - x, dy = pY - y;
verschieben(dx, dy);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Kurve kurve = (Kurve) o;
return super.equals(o) &&
getStartpunkt().equals(kurve.getStartpunkt()) &&
getKontrollpunkt1().equals(kurve.getKontrollpunkt1()) &&
getKontrollpunkt2().equals(kurve.getKontrollpunkt2()) &&
getEndpunkt().equals(kurve.getEndpunkt());
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x=" + x +
",y=" + y +
"x2=" + koordinaten[koordinaten.length - 2] +
",y2=" + koordinaten[koordinaten.length - 1] +
']';
}
}

View File

@ -0,0 +1,108 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.geom.Line2D;
public class Line extends Shape {
protected double x2;
protected double y2;
public Line( double x1, double y1, double x2, double y2 ) {
super(x1, y1);
this.x2 = x2;
this.y2 = y2;
}
public Line( Line line ) {
this(line.x, line.y, line.x2, line.y2);
copyFrom(line);
}
public double getX2() {
return x2;
}
public void setX2( double x ) {
this.x2 = x;
}
public double getY2() {
return y2;
}
public void setY2( double y ) {
this.y2 = y;
}
@Override
public void scale( double factor ) {
super.scale(factor);
x2 *= factor;
y2 *= factor;
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Line ) {
Line pLine = (Line) shape;
x2 = pLine.x2;
y2 = pLine.y2;
}
}
@Override
public Line copy() {
return new Line(this);
}
@Override
public void move( double dx, double dy ) {
super.move(dx, dy);
x2 += dx;
y2 += dx;
}
@Override
public void moveTo( double x, double y ) {
double dx = x2-this.x;
double dy = y2-this.y;
super.moveTo(x, y);
x2 += dx;
y2 += dy;
}
@Override
public void setAnchor( Options.Direction anchor ) {
calculateAnchor(x2 - x, y2 - y, anchor);
}
@Override
public java.awt.Shape getShape() {
return new Line2D.Double(0, 0, x2 - x, y2 - y);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Line pLine = (Line) o;
return super.equals(o) &&
Double.compare(pLine.x2, x2) == 0 &&
Double.compare(pLine.y2, y2) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x1=" + x +
",y1=" + y +
",x2=" + x2 +
",y2=" + y2 +
']';
}
}

View File

@ -1,92 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Line2D;
public class Linie extends Form {
protected double x2;
protected double y2;
public Linie( double pX1, double pY1, double pX2, double pY2 ) {
super(pX1, pY1);
x2 = pX2;
y2 = pY2;
}
public Linie( Linie pLinie ) {
this(pLinie.x, pLinie.y, pLinie.x2, pLinie.y2);
kopiere(pLinie);
}
public void setX2( double pX ) {
this.x2 = x;
}
public void setY2( double pY ) {
this.y2 = y;
}
public double getX2() {
return x2;
}
public double getY2() {
return y2;
}
@Override
public void skalieren( double pFaktor ) {
super.skalieren(pFaktor);
x2 *= pFaktor;
y2 *= pFaktor;
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Linie ) {
Linie linie = (Linie) pForm;
x2 = linie.x2;
y2 = linie.y2;
}
}
@Override
public Linie kopie() {
return new Linie(this);
}
@Override
public void setAnkerpunkt( byte pAnker ) {
ankerBerechnen(x2-x, y2-y, pAnker);
}
@Override
public Shape getShape() {
Line2D.Double linie = new Line2D.Double(0, 0, x2 - x, y2 - y);
return linie;
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Linie linie = (Linie) o;
return super.equals(o) &&
Double.compare(linie.x2, x2) == 0 &&
Double.compare(linie.y2, y2) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x1=" + x +
",y1=" + y +
",x2=" + x2 +
",y2=" + y2 +
']';
}
}

View File

@ -1,137 +0,0 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Vektor;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
public class Pfeil extends Linie {
public static final int OFFEN = 101;
public static final int GESCHLOSSEN = 102;
private static final double BASIS_PFEILGROESSE = 5.0;
protected int pfeilspitze = OFFEN;
protected double pfeilgroesse = 1.0;
public Pfeil( double pX1, double pY1, double pX2, double pY2 ) {
super(pX1, pY1, pX2, pY2);
}
public Pfeil( Vektor pVektor ) {
this(0, 0, pVektor.x, pVektor.y);
}
public Pfeil( double pX, double pY, Vektor pVektor ) {
this(pX, pY, pX + pVektor.x, pY + pVektor.y);
}
public Pfeil( Linie pLinie ) {
this(pLinie.x, pLinie.y, pLinie.x2, pLinie.y2);
kopiere(pLinie);
}
public double getPfeilgroesse() {
return pfeilgroesse;
}
public void setPfeilgroesse( double pPfeilgroesse ) {
pfeilgroesse = pPfeilgroesse;
}
public int getPfeilspitze() {
return pfeilspitze;
}
public void setPfeilspitze( int pPfeilspitze ) {
this.pfeilspitze = pPfeilspitze;
}
public void abbilden( Vektor pVektor ) {
x2 = x + pVektor.x;
y2 = y + pVektor.y;
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Pfeil ) {
Pfeil pfeil = (Pfeil) pForm;
pfeilgroesse = pfeil.pfeilgroesse;
pfeilspitze = pfeil.pfeilspitze;
}
}
@Override
public Pfeil kopie() {
return new Pfeil(this);
}
@Override
public Shape getShape() {
/*Path2D.Double gruppe = new Path2D.Double();
gruppe.append(super.getShape(), false);
gruppe.append(getPfeilspitze(), false);
return gruppe;*/
return super.getShape();
}
protected Shape getSpitze() {
AffineTransform af;
switch( pfeilspitze ) {
case OFFEN:
double len = BASIS_PFEILGROESSE * pfeilgroesse;
Path2D.Double sOffen = new Path2D.Double();
sOffen.moveTo(-len, -len);
sOffen.lineTo(0, 0);
sOffen.lineTo(-len, len);
af = new AffineTransform();
af.translate(x2, y2);
af.rotate(Math.atan2(y2 - y, x2 - x));
return af.createTransformedShape(sOffen);
case GESCHLOSSEN:
default:
int ix = (int) x2, iy = (int) y2, pg = (int) (BASIS_PFEILGROESSE * pfeilgroesse);
Polygon sGeschlossen = new Polygon(
new int[]{0, -pg, -pg},
new int[]{0, -pg, pg},
3
);
af = new AffineTransform();
af.translate(x2, y2);
af.rotate(Math.atan2(y2 - y, x2 - x));
return af.createTransformedShape(sGeschlossen);
}
}
@Override
public void zeichnen( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !sichtbar ) {
return;
}
super.zeichnen(graphics);
Shape spitze = getSpitze();
if( pVerzerrung != null ) {
spitze = pVerzerrung.createTransformedShape(spitze);
}
Color currentColor = graphics.getColor();
if( konturFarbe != null && konturFarbe.getAlpha() > 0.0 ) {
graphics.setColor(konturFarbe);
graphics.setStroke(new BasicStroke((float) konturDicke));
if( pfeilspitze == GESCHLOSSEN ) {
graphics.fill(spitze);
} else {
graphics.draw(spitze);
}
}
graphics.setColor(currentColor);
}
}

View File

@ -0,0 +1,128 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Color;
import schule.ngb.zm.Options;
import schule.ngb.zm.util.ImageLoader;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
public class Picture extends Shape {
// https://stackoverflow.com/questions/14225518/tinting-image-in-java-improvement
protected Color tint;
private BufferedImage image;
private double width;
private double height;
public Picture( String source ) {
this(0, 0, source);
}
public Picture( double x, double y, String source ) {
super(x, y);
image = ImageLoader.loadImage(source);
if( image == null ) {
throw new IllegalArgumentException("Could not initialize image from source " + source);
}
width = image.getWidth();
height = image.getHeight();
setAnchor(CENTER);
}
public Picture( Picture picture ) {
super(picture.getX(), picture.getY());
copyFrom(picture);
}
@Override
public Shape copy() {
return new Picture(this);
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Picture ) {
Picture pic = (Picture) shape;
image = new BufferedImage(pic.image.getWidth(), pic.image.getHeight(), pic.image.getType());
Graphics2D g = image.createGraphics();
g.drawImage(pic.image, 0, 0, null);
g.dispose();
width = image.getWidth();
height = image.getHeight();
setAnchor(shape.getAnchor());
}
}
public double getWidth() {
return width;
}
public void setWidth( double width ) {
scale(width / width);
}
public double getHeight() {
return height;
}
public void setHeight( double height ) {
scale(height / height);
}
public BufferedImage getImage() {
return image;
}
@Override
public void setAnchor( Options.Direction anchor ) {
calculateAnchor(width, height, anchor);
}
@Override
public void scale( double factor ) {
super.scale(factor);
width *= factor;
height *= factor;
}
@Override
public java.awt.Shape getShape() {
return new Rectangle2D.Double(0, 0, width, height);
}
/*
@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 draw( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !visible ) {
return;
}
AffineTransform current = graphics.getTransform();
graphics.transform(getTransform());
graphics.drawImage(image, 0, 0, (int) width, (int) height, null);
graphics.setTransform(current);
}
}

View File

@ -0,0 +1,58 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.geom.Point2D;
public class Point extends Circle {
private static final double POINT_RADIUS = 2.0;
/**
* Erstellt ein Punktobjekt mit den angegebenen Koordinaten.
* @param x
* @param y
*/
public Point( double x, double y ) {
super(x, y, POINT_RADIUS);
}
/**
* Erstellt ein Punktobjekt mit den Koordinaten des übergebenen
* {@link schule.ngb.zm.Vector Vektors}.
* @param point
*/
public Point( schule.ngb.zm.Vector vector ) {
super(vector.x, vector.y, POINT_RADIUS);
}
/**
* Erstellt ein Punktobjekt mit den Koordinaten des übergebenen
* {@link java.awt.geom.Point2D Punktes}.
* @param point
*/
public Point( Point2D point ) {
super(point.getX(), point.getY(), POINT_RADIUS);
}
/**
* Erstellt ein Punktobjekt mit den Koordinaten der angegeben Form.
* @param shape
*/
public Point( Shape shape ) {
super(shape.getX(), shape.getY(), POINT_RADIUS);
}
@Override
public void scale( double factor ) {
// Skalierung ist für Punkte deaktiviert
return;
}
@Override
public void setAnchor( Options.Direction anchor ) {
// Punkte sind immer im Zentrum verankert
calculateAnchor(radius + radius, radius + radius, CENTER);
}
}

View File

@ -0,0 +1,82 @@
package schule.ngb.zm.formen;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
public class Polygon extends Shape {
protected Point2D[] points;
public Polygon( double x, double y, Point2D... points ) {
super(x, y);
this.points = new Point2D[points.length];
for( int i = 0; i < points.length; i++ ) {
this.points[i] = new Point2D.Double(points[i].getX() - x, points[i].getY() - y);
}
}
public Polygon( Point2D... points ) {
this.points = new Point2D[points.length];
for( int i = 0; i < points.length; i++ ) {
if( i == 0 ) {
x = points[i].getX();
y = points[i].getY();
}
this.points[i] = new Point2D.Double(points[i].getX() - x, points[i].getY() - y);
}
}
public Polygon( double x1, double y1, double x2, double y2, double... coordinates ) {
super(x1, y1);
int numPoints = coordinates.length / 2 + 2;
points = new Point2D[numPoints];
this.points[0] = new Point2D.Double(x1, y1);
this.points[1] = new Point2D.Double(x2 - x1, y2 - y1);
for( int i = 0; i < numPoints - 2; i += 1 ) {
this.points[i + 2] = new Point2D.Double(coordinates[i * 2] - x1, coordinates[i * 2 + 1] - y1);
}
}
public Polygon( Polygon polygon ) {
super(polygon.x, polygon.y);
copyFrom(polygon);
}
public Point2D[] getPoints() {
return points;
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Polygon ) {
Polygon v = (Polygon) shape;
points = new Point2D[v.points.length];
for( int i = 0; i < v.points.length; i++ ) {
points[i] = new Point2D.Double(v.points[i].getX(), v.points[i].getY());
}
}
}
@Override
public Shape copy() {
return new Polygon(this);
}
@Override
public java.awt.Shape getShape() {
Path2D shape = new Path2D.Double();
//shape.moveTo(points[0].getX(), points[0].getY());
shape.moveTo(0, 0);
for( int i = 1; i < points.length; i++ ) {
shape.lineTo(points[i].getX(), points[i].getY());
}
shape.closePath();
return shape;
}
}

View File

@ -1,34 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.geom.Point2D;
public class Punkt extends Kreis {
private static final double PUNKT_RADIUS = 2.0;
public Punkt( double pX, double pY ) {
super(pX, pY, PUNKT_RADIUS);
}
public Punkt( Point2D pPunkt ) {
super(pPunkt.getX(), pPunkt.getY(), PUNKT_RADIUS);
}
public Punkt( Form pForm ) {
super(pForm.getX(), pForm.getY(), PUNKT_RADIUS);
}
@Override
public void skalieren( double pFaktor ) {
// Skalierung ist für Punkte deaktiviert
return;
}
@Override
public void setAnkerpunkt( byte pAnker ) {
// Punkte sind immer im Zentrum verankert
ankerBerechnen(radius + radius, radius + radius, ZENTRUM);
}
}

View File

@ -0,0 +1,36 @@
package schule.ngb.zm.formen;
import java.awt.geom.Point2D;
import java.util.Arrays;
public class Quad extends Polygon {
public Quad( double x, double y, Point2D... points ) {
super(x, y, Arrays.copyOf(points, 4));
if( points.length < 4 ) {
throw new IllegalArgumentException("A quadrilateral requires exactly four points.");
}
}
public Quad( Point2D... points ) {
super(Arrays.copyOf(points, 4));
if( points.length < 4 ) {
throw new IllegalArgumentException("A quadrilateral requires exactly four points.");
}
}
public Quad( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 ) {
super(x1, y1, x2, y2, x3, y3, x4, y4);
}
public Quad( Quad pViereck ) {
super(pViereck.x, pViereck.y);
copyFrom(pViereck);
}
@Override
public Shape copy() {
return new Quad(this);
}
}

View File

@ -1,38 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Path2D;
public class Raute extends Drache {
private double breite;
private double hoehe;
public Raute( double pX, double pY, double pBreite, double pHoehe ) {
super(pX, pY, pBreite, pHoehe, 0.5);
setAnkerpunkt(ZENTRUM);
}
public Raute( Raute pRaute ) {
this(pRaute.x, pRaute.y, pRaute.breite, pRaute.hoehe);
kopiere(pRaute);
}
@Override
public void setVerhaeltnis( double pVerhaeltnis ) {
super.setVerhaeltnis(0.5);
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
super.setVerhaeltnis(0.5);
}
@Override
public Drache kopie() {
return new Drache(this);
}
}

View File

@ -1,107 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class Rechteck extends Form {
protected double breite;
protected double hoehe;
public Rechteck( double pX, double pY, double pBreite, double pHoehe ) {
super(pX, pY);
breite = pBreite;
hoehe = pHoehe;
setAnkerpunkt(NORDWESTEN);
}
public Rechteck( Rechteck pRechteck ) {
this(
pRechteck.x, pRechteck.y,
pRechteck.breite, pRechteck.hoehe);
kopiere(pRechteck);
}
public Rechteck( Form pForm ) {
Shape s = pForm.getShape();
s = pForm.getVerzerrung().createTransformedShape(s);
Rectangle2D bounds = s.getBounds2D();
x = bounds.getX();
y = bounds.getY();
breite = bounds.getWidth();
hoehe = bounds.getHeight();
fuellFarbe = null;
konturArt = GESTRICHELT;
}
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;
}
@Override
public Rechteck kopie() {
return new Rechteck(this);
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Rechteck ) {
Rechteck rechteck = (Rechteck) pForm;
breite = rechteck.breite;
hoehe = rechteck.hoehe;
}
}
@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 void setAnkerpunkt( byte pAnker ) {
ankerBerechnen(breite, hoehe, pAnker);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Rechteck rechteck = (Rechteck) o;
return super.equals(o) &&
Double.compare(rechteck.breite, breite) == 0 &&
Double.compare(rechteck.hoehe, hoehe) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x=" + x +
",y=" + y +
",breite=" + breite +
",hoehe=" + hoehe +
']';
}
}

View File

@ -0,0 +1,108 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.geom.Rectangle2D;
public class Rectangle extends Shape {
protected double width;
protected double height;
public Rectangle( double x, double y, double width, double height ) {
super(x, y);
this.width = width;
this.height = height;
setAnchor(NORTHWEST);
}
public Rectangle( Rectangle pRechteck ) {
this(
pRechteck.x, pRechteck.y,
pRechteck.width, pRechteck.height);
copyFrom(pRechteck);
}
public Rectangle( Shape pShape ) {
java.awt.Shape s = pShape.getShape();
s = pShape.getTransform().createTransformedShape(s);
Rectangle2D bounds = s.getBounds2D();
x = bounds.getX();
y = bounds.getY();
width = bounds.getWidth();
height = bounds.getHeight();
fillColor = null;
strokeType = DASHED;
}
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;
}
@Override
public Rectangle copy() {
return new Rectangle(this);
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Rectangle ) {
Rectangle rechteck = (Rectangle) shape;
width = rechteck.width;
height = rechteck.height;
}
}
@Override
public void scale( double factor ) {
super.scale(factor);
width *= factor;
height *= factor;
}
@Override
public java.awt.Shape getShape() {
return new Rectangle2D.Double(0, 0, width, height);
}
@Override
public void setAnchor( Options.Direction anchor ) {
calculateAnchor(width, height, anchor);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Rectangle rechteck = (Rectangle) o;
return super.equals(o) &&
Double.compare(rechteck.width, width) == 0 &&
Double.compare(rechteck.height, height) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x=" + x +
",y=" + y +
",width=" + width +
",height=" + height +
']';
}
}

View File

@ -0,0 +1,32 @@
package schule.ngb.zm.formen;
public class Rhombus extends Kite {
public Rhombus( double x, double y, double width, double height ) {
super(x, y, width, height, 0.5);
setAnchor(CENTER);
}
public Rhombus( Rhombus rhombus ) {
this(rhombus.x, rhombus.y, rhombus.width, rhombus.height);
this.copyFrom(rhombus);
}
@Override
public void setRatio( double ratio ) {
// Für eine Raute ist das Verhältnis immer 50/
super.setRatio(0.5);
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
super.setRatio(0.5);
}
@Override
public Kite copy() {
return new Kite(this);
}
}

View File

@ -0,0 +1,57 @@
package schule.ngb.zm.formen;
import java.awt.geom.RoundRectangle2D;
public class RoundedRectangle extends Rectangle {
protected double borderRadius = 1.0;
public RoundedRectangle( double x, double y, double width, double height, double borderRadius ) {
super(x, y, width, height);
this.borderRadius = borderRadius;
}
public RoundedRectangle( Rectangle pRechteck ) {
super(
pRechteck.x, pRechteck.y,
pRechteck.width, pRechteck.height);
copyFrom(pRechteck);
}
@Override
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof RoundedRectangle ) {
RoundedRectangle rechteck = (RoundedRectangle) shape;
borderRadius = rechteck.borderRadius;
}
}
@Override
public java.awt.Shape getShape() {
return new RoundRectangle2D.Double(
0, 0, width, height, borderRadius, borderRadius
);
}
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
RoundedRectangle rechteck = (RoundedRectangle) o;
return super.equals(o) &&
Double.compare(rechteck.borderRadius, borderRadius) == 0;
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"x=" + x +
",y=" + y +
",width=" + width +
",height=" + height +
",rundung=" + borderRadius +
']';
}
}

View File

@ -0,0 +1,291 @@
package schule.ngb.zm.formen;
import org.jetbrains.annotations.NotNull;
import schule.ngb.zm.Options;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public abstract class Shape extends FilledShape {
protected double x;
protected double y;
protected double rotation = 0.0;
protected double scale = 1.0;
protected boolean visible = true;
protected Point2D.Double anchor = new Point2D.Double();
public Shape( double x, double y ) {
this.x = x;
this.y = y;
}
public Shape() {
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 getRotation() {
return rotation;
}
public double getScale() {
return scale;
}
public boolean isVisible() {
return visible;
}
public void hide() {
visible = false;
}
public void show() {
visible = true;
}
public void toggle() {
visible = !visible;
}
public Point2D.Double getAnchor() {
return new Point2D.Double(anchor.x, anchor.y);
}
/**
* Setzt den Ankerpunkt der Form basierend auf der angegebenen
* {@link Options.Direction Richtung}.
*
* Für das Setzen des Ankers muss das {@link #getBounds() begrenzende
* Rechteck} berechnet werden. Unterklassen sollten die Methode
* überschreiben, wenn der Anker auch direkt gesetzt werden kann.
* @param anchor
*/
public void setAnchor( Options.Direction anchor ) {
java.awt.Shape shape = getShape();
if( shape != null ) {
Rectangle2D bounds = shape.getBounds2D();
calculateAnchor(bounds.getWidth(), bounds.getHeight(), anchor);
} else {
this.anchor.x = 0;
this.anchor.y = 0;
}
}
/**
* Setzt den Ankerpunkt explizit auf den angegebenen
* @param anchor
*/
public void setAnchor( Point2D.Double anchor ) {
setAnchor(anchor, false);
}
public void setAnchor( Point2D.Double anchor, boolean isRelative ) {
if( anchor != null ) {
setAnchor(anchor.x, anchor.y, isRelative);
} else {
setAnchor(0, 0, true);
}
}
public void setAnchor( double x, double y ) {
setAnchor(x, y, false);
}
public void setAnchor( double x, double y, boolean isRelative ) {
if( isRelative ) {
this.anchor.x = x;
this.anchor.y = y;
} else {
this.anchor.x = this.x-x;
this.anchor.y = this.y-y;
}
}
/**
* Hilfsmethode zur Berechnung eines Ankerpunktes relativ zu den angegebenen
* Begrenzungen basierend aus {@link #x}-, {@link #y}-Koordinate und
* <var>width</var> / <var>height</var> (Breite / Höhe).
* @param width
* @param height
* @param anchor
*/
protected void calculateAnchor( double width, double height, @NotNull Options.Direction anchor ) {
double bHalf = width * .5, hHalf = height * .5;
// pAnker == CENTER
this.anchor.x = bHalf;
this.anchor.y = hHalf;
if( NORTH.is(anchor) ) {
this.anchor.y -= hHalf;
}
if( SOUTH.is(anchor) ) {
this.anchor.y += hHalf;
}
if( WEST.is(anchor) ) {
this.anchor.x -= bHalf;
}
if( EAST.is(anchor) ) {
this.anchor.x += bHalf;
}
}
/**
* Kopiert die Eigenschaften der übergebenen Form in diese.
*
* Unterklassen sollten diese Methode überschreiben, um weitere Eigenschaften
* zu kopieren (zum Beispiel den Radius eines Kreises). Mit dem Aufruf
* <code>super.copyFrom(shape)</code> sollten die Basiseigenschaften
* kopiert werden.
* @param shape
*/
public void copyFrom( Shape shape ) {
moveTo(shape.x, shape.y);
setFillColor(shape.getFillColor());
setStrokeColor(shape.getStrokeColor());
setStrokeWeight(shape.getStrokeWeight());
setStrokeType(shape.getStrokeType());
visible = shape.isVisible();
rotation = shape.rotation;
scale(shape.scale);
setAnchor(shape.getAnchor());
}
public abstract Shape copy();
public abstract java.awt.Shape getShape();
public Rectangle getBounds() {
return new Rectangle(this);
}
public void move( double dx, double dy ) {
x += dx;
y += dy;
}
public void moveTo( double x, double y ) {
this.x = x;
this.y = y;
}
public void scale( double factor ) {
scale = factor;
anchor.x *= factor;
anchor.y *= factor;
}
public void scaleBy( double factor ) {
scale(scale * factor);
}
public void rotate( double angle ) {
this.rotation += angle % 360;
}
public void rotateTo( double angle ) {
this.rotation = angle % 360;
}
/*public void shear( double dx, double dy ) {
verzerrung.shear(dx, dy);
}*/
public AffineTransform getTransform() {
AffineTransform transform = new AffineTransform();
transform.translate(x, y);
transform.rotate(Math.toRadians(rotation));
//transform.scale(scale, scale);
transform.translate(-anchor.x, -anchor.y);
return transform;
}
/**
* Zeichnet die Form.
*
* @param graphics
*/
@Override
public final void draw( Graphics2D graphics ) {
draw(graphics, getTransform());
}
/**
* Zeichnet die Form, aber wendet zuvor noch eine zusätzliche Transformations-
* matrix an. Wird u.A. von der {@link ShapeGroup} verwendet.
*
* @param graphics
* @param pVerzerrung
*/
public void draw( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !visible ) {
return;
}
java.awt.Shape shape = getShape();
if( shape != null ) {
if( pVerzerrung != null ) {
shape = pVerzerrung.createTransformedShape(shape);
}
Color currentColor = graphics.getColor();
if( fillColor != null && fillColor.getAlpha() > 0 ) {
graphics.setColor(fillColor.getColor());
graphics.fill(shape);
}
if( strokeColor != null && strokeColor.getAlpha() > 0
&& strokeWeight > 0.0 ) {
graphics.setColor(strokeColor.getColor());
graphics.setStroke(createStroke());
graphics.draw(shape);
}
graphics.setColor(currentColor);
}
}
/**
* Vergleicht die Form mit einem anderen Objekt. Handelt es sich bei dem
* Objekt um eine andere Form, werden Position, Drehwinkel und Skalierung
* verglichen. Unterklassen überschreiben die Methode, um weitere
* Eigenschaften zu berücksichtigen.
* <p>
* Die Eigenschaften von {@link FilledShape} und {@link StrokedShape} werden
* nicht verglichen.
*
* @param o Ein anderes Objekt.
* @return
*/
@Override
public boolean equals( Object o ) {
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Shape pShape = (Shape) o;
return Double.compare(pShape.x, x) == 0 &&
Double.compare(pShape.y, y) == 0 &&
Double.compare(pShape.rotation, rotation) == 0 &&
Double.compare(pShape.scale, scale) == 0;
}
}

View File

@ -0,0 +1,138 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ShapeGroup extends Shape {
private List<Shape> shapes;
public ShapeGroup() {
super();
shapes = new ArrayList<>(10);
}
public ShapeGroup( double x, double y ) {
super(x, y);
shapes = new ArrayList<>(10);
}
public ShapeGroup( double x, double y, Shape... shapes ) {
super(x, y);
this.shapes = new ArrayList<>(shapes.length);
for( Shape pShape : shapes ) {
this.shapes.add(pShape);
}
setAnchor(CENTER);
}
public Shape copy() {
// TODO: implement?
return null;
}
public void add( Shape... shapes ) {
for( Shape shape : shapes ) {
add(shape, false);
}
}
public void add( Shape pShape, boolean relative ) {
if( relative ) {
pShape.x = pShape.x - x;
pShape.y = pShape.y - y;
}
shapes.add(pShape);
}
public void removeAll() {
shapes.clear();
}
public List<Shape> getShapes() {
return shapes;
}
public <ShapeType extends Shape> List<ShapeType> getShapes( Class<ShapeType> typeClass ) {
LinkedList<ShapeType> list = new LinkedList<>();
for( Shape s: shapes ) {
if( typeClass.getClass().isInstance(s) ) {
list.add((ShapeType)s);
}
}
return list;
}
public void remove( Shape shape ) {
shapes.remove(shape);
}
public Shape get( int index ) {
if( index < shapes.size() ) {
return shapes.get(index);
} else {
return null;
}
}
public boolean contains( Shape shape ) {
return shapes.contains(shape);
}
public int size() {
return shapes.size();
}
@Override
public void setAnchor( Options.Direction anchor ) {
double minx = Double.MAX_VALUE, miny = Double.MAX_VALUE,
maxx = Double.MIN_VALUE, maxy = Double.MIN_VALUE;
for( Shape pShape : shapes ) {
Rectangle bounds = pShape.getBounds();
if( bounds.x < minx )
minx = bounds.x;
if( bounds.y < miny )
miny = bounds.y;
if( bounds.x+bounds.width > maxx )
maxx = bounds.x+bounds.width;
if( bounds.y+bounds.height > maxy )
maxy = bounds.y+bounds.height;
}
calculateAnchor(maxx-minx, maxy-miny, anchor);
}
@Override
public java.awt.Shape getShape() {
Path2D.Double gruppe = new Path2D.Double();
for( Shape pShape : shapes ) {
gruppe.append(pShape.getShape(), false);
}
return gruppe;
}
@Override
public void draw( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !visible ) {
return;
}
AffineTransform verzerrung = new AffineTransform();
verzerrung.translate(x, y);
verzerrung.rotate(Math.toRadians(rotation));
//verzerrung.scale(skalierung, skalierung);
verzerrung.translate(-anchor.x, -anchor.y);
for( Shape f: shapes ) {
AffineTransform af = f.getTransform();
af.preConcatenate(verzerrung);
f.draw(graphics, af);
}
}
}

View File

@ -0,0 +1,69 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Layer;
import java.awt.*;
import java.util.LinkedList;
public class ShapesLayer extends Layer {
protected boolean clearBeforeDraw = true;
private LinkedList<Shape> formen;
public ShapesLayer() {
super();
formen = new LinkedList<Shape>();
}
public ShapesLayer( int width, int height ) {
super(width, height);
formen = new LinkedList<Shape>();
}
public void add( Shape... pFormen ) {
synchronized( formen ) {
for( Shape f : pFormen ) {
formen.add(f);
}
}
}
public void showAll() {
synchronized( formen ) {
for( Shape pShape : formen ) {
pShape.hide();
}
}
}
public void hideAll() {
synchronized( formen ) {
for( Shape pShape : formen ) {
pShape.show();
}
}
}
public java.util.List<Shape> getShapes() {
return formen;
}
@Override
public void draw( Graphics2D pGraphics ) {
if( clearBeforeDraw ) {
clear();
}
synchronized( formen ) {
for( Shape pShape : formen ) {
if( pShape.isVisible() ) {
pShape.draw(drawing);
}
}
}
super.draw(pGraphics);
}
}

View File

@ -0,0 +1,104 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Color;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Drawable;
import schule.ngb.zm.Options;
import java.awt.*;
public abstract class StrokedShape extends Constants implements Drawable {
protected Color strokeColor = STD_STROKECOLOR;
protected double strokeWeight = STD_STROKEWEIGHT;
protected Options.StrokeType strokeType = SOLID;
public Color getStrokeColor() {
return strokeColor;
}
public void setStrokeColor( Color color ) {
this.strokeColor = color;
}
public void setStrokeColor( int gray ) {
setStrokeColor(gray, gray, gray, 255);
}
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 double getStrokeWeight() {
return strokeWeight;
}
public void setStrokeWeight( double weight ) {
this.strokeWeight = weight;
}
public Options.StrokeType getStrokeType() {
return strokeType;
}
/**
* Setzt den Typ der Kontur. Erlaubte Werte sind {@link #DASHED},
* {@link #DOTTED} und {@link #SOLID}.
* @param type
*/
public void setStrokeType( Options.StrokeType type ) {
this.strokeType = DASHED;
}
@Override
public abstract void draw( Graphics2D graphics );
/**
* Erstellt ein {@link Stroke} Objekt für den Konturtyp.
* @return
*/
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);
case SOLID:
default:
return new BasicStroke(
(float) strokeWeight,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
}
}
public void resetStroke() {
setStrokeColor(STD_STROKECOLOR);
setStrokeWeight(STD_STROKEWEIGHT);
setStrokeType(SOLID);
}
}

View File

@ -1,56 +1,56 @@
package schule.ngb.zm.formen;
import schule.ngb.zm.Options;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
public class Text extends Form {
private static final int DFT_FONT_SIZE = 14;
public class Text extends Shape {
protected String text;
protected Font schriftart;
protected Font font;
protected int breite = 0, hoehe = 0, ascent = 0;
protected int width = 0, height = 0, ascent = 0;
public Text( double pX, double pY, String pText ) {
super(pX, pY);
schriftart = new Font(Font.SANS_SERIF, Font.PLAIN, DFT_FONT_SIZE);
setText(pText);
public Text( double x, double y, String text ) {
super(x, y);
font = new Font(Font.SANS_SERIF, Font.PLAIN, STD_FONTSIZE);
setText(text);
}
public Text( Text pText ) {
super(pText.getX(), pText.getY());
kopiere(pText);
public Text( Text text ) {
super(text.getX(), text.getY());
copyFrom(text);
}
public Form kopie() {
public Shape copy() {
return new Text(this);
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Text ) {
Text pText = (Text)pForm;
public void copyFrom( Shape shape ) {
super.copyFrom(shape);
if( shape instanceof Text ) {
Text pText = (Text) shape;
this.text = pText.getText();
this.schriftart = pText.getSchriftart();
this.font = pText.getFont();
}
}
@Override
public void skalieren( double pFaktor ) {
super.skalieren(pFaktor);
setSchriftgroesse(schriftart.getSize2D()*pFaktor);
public void scale( double factor ) {
super.scale(factor);
setFontsize(font.getSize2D() * factor);
}
public Font getSchriftart() {
return schriftart;
public Font getFont() {
return font;
}
public void setSchriftgroesse( double pGroesse ) {
schriftart = schriftart.deriveFont((float)pGroesse);
public void setFontsize( double size ) {
font = font.deriveFont((float) size);
setText(text);
}
@ -62,34 +62,34 @@ public class Text extends Form {
text = pText;
Canvas metricsCanvas = new Canvas();
FontMetrics metrics = metricsCanvas.getFontMetrics(schriftart);
breite = metrics.stringWidth(text);
hoehe = metrics.getDescent() + metrics.getAscent();
FontMetrics metrics = metricsCanvas.getFontMetrics(font);
width = metrics.stringWidth(text);
height = metrics.getDescent() + metrics.getAscent();
ascent = metrics.getAscent();
setAnkerpunkt(ZENTRUM);
setAnchor(CENTER);
}
public double getBreite() {
return breite;
public double getWidth() {
return width;
}
public double getHoehe() {
return hoehe;
public double getHeight() {
return height;
}
public void setAnkerpunkt( byte pAnker ) {
ankerBerechnen(breite, ascent - hoehe, pAnker);
public void setAnchor( Options.Direction anchor ) {
calculateAnchor(width, ascent - height, anchor);
}
@Override
public Shape getShape() {
return new Rectangle2D.Double(0, 0, breite, hoehe);
public java.awt.Shape getShape() {
return new Rectangle2D.Double(0, 0, width, height);
}
@Override
public void zeichnen( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !sichtbar ) {
public void draw( Graphics2D graphics, AffineTransform pVerzerrung ) {
if( !visible ) {
return;
}
@ -99,11 +99,11 @@ public class Text extends Form {
AffineTransform af = graphics.getTransform();
// Neue Werte setzen
graphics.setFont(schriftart);
graphics.setColor(konturFarbe);
graphics.transform(getVerzerrung());
graphics.setFont(font);
graphics.setColor(strokeColor.getColor());
graphics.transform(pVerzerrung);
// Text zeichnen
// Draw text
FontMetrics fm = graphics.getFontMetrics();
//graphics.drawString(text, (float) (x - fm.stringWidth(text)/2.0), (float) (y + fm.getDescent()));
graphics.drawString(text, 0, 0);
@ -121,13 +121,15 @@ public class Text extends Form {
Text text = (Text) o;
return super.equals(o) &&
text.equals(text.text) &&
schriftart.equals(text.schriftart);
font.equals(text.font);
}
@Override
public String toString() {
return getClass().getCanonicalName() + "[" +
"text=" + text +
"text=" + text + ',' +
"font=" + font.getName() + ',' +
"size=" + font.getSize() +
']';
}

View File

@ -0,0 +1,36 @@
package schule.ngb.zm.formen;
import java.awt.geom.Point2D;
import java.util.Arrays;
public class Triangle extends Polygon {
public Triangle( double x, double y, Point2D... points ) {
super(x, y, Arrays.copyOf(points, 3));
if( points.length < 3 ) {
throw new IllegalArgumentException("A triangle requires exactly three points.");
}
}
public Triangle( Point2D... points ) {
super(Arrays.copyOf(points, 3));
if( points.length < 3 ) {
throw new IllegalArgumentException("A triangle requires exactly three points.");
}
}
public Triangle( double x1, double y1, double x2, double y2, double x3, double y3 ) {
super(x1, y1, x2, y2, x3, y3);
}
public Triangle( Triangle triangle ) {
super(triangle.x, triangle.y);
copyFrom(triangle);
}
@Override
public Shape copy() {
return new Triangle(this);
}
}

View File

@ -1,72 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.Arrays;
public class Vieleck extends Form {
protected Point2D[] ecken;
public Vieleck( double pX, double pY, Point2D... pEcken ) {
super(pX, pY);
ecken = new Point2D[pEcken.length];
for( int i = 0; i < pEcken.length; i++ ) {
ecken[i] = new Point2D.Double(pEcken[i].getX()-pX, pEcken[i].getY()-pY);
}
}
public Vieleck( Point2D... pEcken ) {
super();
ecken = new Point2D[pEcken.length];
for( int i = 0; i < pEcken.length; i++ ) {
if( i == 0 ) {
x = pEcken[i].getX();
y = pEcken[i].getY();
}
ecken[i] = new Point2D.Double(pEcken[i].getX()-x, pEcken[i].getY()-y);
}
}
public Vieleck( Vieleck pVieleck ) {
this(pVieleck.x, pVieleck.y);
kopiere(pVieleck);
}
public Point2D[] getEcken() {
return ecken;
}
@Override
public void kopiere( Form pForm ) {
super.kopiere(pForm);
if( pForm instanceof Vieleck ) {
Vieleck v = (Vieleck) pForm;
ecken = new Point2D[v.ecken.length];
for( int i = 0; i < v.ecken.length; i++ ) {
ecken[i] = new Point2D.Double(v.ecken[i].getX(), v.ecken[i].getY());
}
}
}
@Override
public Form kopie() {
return new Vieleck(this);
}
@Override
public Shape getShape() {
Path2D shape = new Path2D.Double();
shape.moveTo(ecken[0].getX(), ecken[0].getY());
for( int i = 1; i < ecken.length; i++ ) {
shape.lineTo(ecken[i].getX(), ecken[i].getY());
}
shape.closePath();
return shape;
}
}

View File

@ -1,34 +0,0 @@
package schule.ngb.zm.formen;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.Arrays;
public class Viereck extends Vieleck {
public Viereck( double pX, double pY, Point2D... pEcken ) {
super(pX, pY, Arrays.copyOf(pEcken, 4));
if( pEcken.length < 4 ) {
throw new IllegalArgumentException("Ein Viereck muss genau vier Eckpunkte besitzen.");
}
}
public Viereck( Point2D... pEcken ) {
super(Arrays.copyOf(pEcken, 4));
if( pEcken.length < 4 ) {
throw new IllegalArgumentException("Ein Viereck muss genau vier Eckpunkte besitzen.");
}
}
public Viereck( Viereck pViereck ) {
super(pViereck.x, pViereck.y);
kopiere(pViereck);
}
@Override
public Form kopie() {
return new Viereck(this);
}
}

View File

@ -0,0 +1,141 @@
package schule.ngb.zm.util;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
public class ImageLoader {
public static boolean cacheing = true;
private static HashMap<String, BufferedImage> imageCache = new HashMap<>();
public static BufferedImage loadImage( String source ) {
return loadImage(source, cacheing);
}
/**
* Läadt ein Bild von der angegebenen Quelle <var>source</var> und gibt das
* Bild zurück oder <code>null</code>, wenn das Bild nicht geladen werden
* konnte. Ist ein Bild mit der angegebenen Quelle im Cache, wird das
* gechachete Bild zurückgegeben. Dies kann mit <code>cacheing = false</code>
* verhindert werden.
* <p>
* Wurde chacheing global deaktiviert, kann mit <code>cacheing = true</code>
* das Bild trotzdem aus dem Cache geladen werden, wenn es vorhanden ist.
*
* @param source
* @param cacheing
* @return
*/
public static BufferedImage loadImage( String source, boolean cacheing ) {
if( source == null || source.length() == 0 )
throw new IllegalArgumentException("Image source may not be null or empty.");
if( cacheing && imageCache.containsKey(source) ) {
BufferedImage cachedImage = imageCache.get(source);
if( cachedImage != null ) {
return cachedImage;
}
}
try {
BufferedImage img;
// Load image from working dir
File file = new File(source);
if( file.isFile() ) {
img = ImageIO.read(file);
} else {
// load ressource relative to .class-file
URL url = ImageLoader.class.getResource(source);
// relative to ClassLoader
if( url == null ) {
url = ImageLoader.class.getClassLoader().getResource(source);
}
// load form web or jar-file
if( url == null ) {
url = new URL(source);
}
img = ImageIO.read(url);
}
if( cacheing && img != null ) {
imageCache.put(source, img);
}
return img;
} catch( IOException ioe ) {
return null;
}
}
/**
* Loads an image into the cache with a user specified name that may differ
* from the image source string.
*
* @param name
* @param source
* @return
*/
public static boolean preloadImage( String name, String source ) {
BufferedImage img = loadImage(source, true);
if( cacheing && img != null ) {
imageCache.put(name, img);
return true;
}
return false;
}
/**
* Checks if an image with the given name is currently cached.
*
* @param name
* @return
*/
public static boolean isCached( String name ) {
if( imageCache.containsKey(name) ) {
return imageCache.get(name) != null;
}
return false;
}
/**
* Remove the specified key from the cache.
*
* @param name
*/
public static void invalidateCache( String name ) {
if( imageCache.containsKey(name) ) {
imageCache.remove(name);
}
}
/**
* Prevents caching for the specified source.
*
* @param source
*/
public static void noCache( String source ) {
imageCache.put(source, null);
}
public static void clearCache() {
imageCache.clear();
}
public static void enableCaching() {
cacheing = true;
}
public static void disableCaching() {
cacheing = false;
}
}

View File

@ -0,0 +1,349 @@
package schule.ngb.zm.util;
import javax.swing.text.AbstractDocument;
/**
* <p>
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
* </p>
* <p>
* Generische Klasse List<ContentType>
* </p>
* <p>
* Objekt der generischen Klasse List verwalten beliebig viele linear
* angeordnete Objekte vom Typ ContentType. Auf hoechstens ein Listenobjekt,
* aktuellesObjekt genannt, kann jeweils zugegriffen werden.<br />
* Wenn eine Liste leer ist, vollstaendig durchlaufen wurde oder das aktuelle
* Objekt am Ende der Liste geloescht wurde, gibt es kein aktuelles Objekt.<br />
* Das erste oder das letzte Objekt einer Liste koennen durch einen Auftrag zum
* aktuellen Objekt gemacht werden. Ausserdem kann das dem aktuellen Objekt
* folgende Listenobjekt zum neuen aktuellen Objekt werden. <br />
* Das aktuelle Objekt kann gelesen, veraendert oder geloescht werden. Ausserdem
* kann vor dem aktuellen Objekt ein Listenobjekt eingefuegt werden.
* </p>
*
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
* @version Generisch_06 2015-10-25
*/
public class List<ContentType> {
/* --------- Anfang der privaten inneren Klasse -------------- */
private class ListNode {
private ContentType contentObject;
private ListNode next;
/**
* Ein neues Objekt wird erschaffen. Der Verweis ist leer.
*
* @param pContent das Inhaltsobjekt vom Typ ContentType
*/
private ListNode(ContentType pContent) {
contentObject = pContent;
next = null;
}
/**
* Der Inhalt des Knotens wird zurueckgeliefert.
*
* @return das Inhaltsobjekt des Knotens
*/
public ContentType getContentObject() {
return contentObject;
}
/**
* Der Inhalt dieses Kontens wird gesetzt.
*
* @param pContent das Inhaltsobjekt vom Typ ContentType
*/
public void setContentObject(ContentType pContent) {
contentObject = pContent;
}
/**
* Der Nachfolgeknoten wird zurueckgeliefert.
*
* @return das Objekt, auf das der aktuelle Verweis zeigt
*/
public ListNode getNextNode() {
return this.next;
}
/**
* Der Verweis wird auf das Objekt, das als Parameter uebergeben
* wird, gesetzt.
*
* @param pNext der Nachfolger des Knotens
*/
public void setNextNode(ListNode pNext) {
this.next = pNext;
}
}
/* ----------- Ende der privaten inneren Klasse -------------- */
// erstes Element der Liste
ListNode first;
// letztes Element der Liste
ListNode last;
// aktuelles Element der Liste
ListNode current;
/**
* Eine leere Liste wird erzeugt.
*/
public List() {
first = null;
last = null;
current = null;
}
/**
* Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthaelt,
* sonst liefert sie den Wert false.
*
* @return true, wenn die Liste leer ist, sonst false
*/
public boolean isEmpty() {
// Die Liste ist leer, wenn es kein erstes Element gibt.
return first == null;
}
/**
* Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt,
* sonst liefert sie den Wert false.
*
* @return true, falls Zugriff moeglich, sonst false
*/
public boolean hasAccess() {
// Es gibt keinen Zugriff, wenn current auf kein Element verweist.
return current != null;
}
/**
* Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses
* nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in
* der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach
* Ausfuehrung des Auftrags kein aktuelles Objekt, d.h. hasAccess() liefert
* den Wert false.
*/
public void next() {
if (this.hasAccess()) {
current = current.getNextNode();
}
}
/**
* Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles
* Objekt. Ist die Liste leer, geschieht nichts.
*/
public void toFirst() {
if (!isEmpty()) {
current = first;
}
}
/**
* Falls die Liste nicht leer ist, wird das letzte Objekt der Liste
* aktuelles Objekt. Ist die Liste leer, geschieht nichts.
*/
public void toLast() {
if (!isEmpty()) {
current = last;
}
}
/**
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
* aktuelle Objekt zurueckgegeben, andernfalls (hasAccess() == false) gibt
* die Anfrage den Wert null zurueck.
*
* @return das aktuelle Objekt (vom Typ ContentType) oder null, wenn es
* kein aktuelles Objekt gibt
*/
public ContentType getContent() {
if (this.hasAccess()) {
return current.getContentObject();
} else {
return null;
}
}
/**
* Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent
* ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst
* geschieht nichts.
*
* @param pContent
* das zu schreibende Objekt vom Typ ContentType
*/
public void setContent(ContentType pContent) {
// Nichts tun, wenn es keinen Inhalt oder kein aktuelles Element gibt.
if (pContent != null && this.hasAccess()) {
current.setContentObject(pContent);
}
}
/**
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues
* Objekt vor dem aktuellen Objekt in die Liste eingefuegt. Das aktuelle
* Objekt bleibt unveraendert. <br />
* Wenn die Liste leer ist, wird pContent in die Liste eingefuegt und es
* gibt weiterhin kein aktuelles Objekt (hasAccess() == false). <br />
* Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste
* nicht leer ist oder pContent gleich null ist, geschieht nichts.
*
* @param pContent
* das einzufuegende Objekt vom Typ ContentType
*/
public void insert(ContentType pContent) {
if (pContent != null) { // Nichts tun, wenn es keinen Inhalt gibt.
if (this.hasAccess()) { // Fall: Es gibt ein aktuelles Element.
// Neuen Knoten erstellen.
ListNode newNode = new ListNode(pContent);
if (current != first) { // Fall: Nicht an erster Stelle einfuegen.
ListNode previous = this.getPrevious(current);
newNode.setNextNode(previous.getNextNode());
previous.setNextNode(newNode);
} else { // Fall: An erster Stelle einfuegen.
newNode.setNextNode(first);
first = newNode;
}
} else { //Fall: Es gibt kein aktuelles Element.
if (this.isEmpty()) { // Fall: In leere Liste einfuegen.
// Neuen Knoten erstellen.
ListNode newNode = new ListNode(pContent);
first = newNode;
last = newNode;
}
}
}
}
/**
* Falls pContent gleich null ist, geschieht nichts.<br />
* Ansonsten wird ein neues Objekt pContent am Ende der Liste eingefuegt.
* Das aktuelle Objekt bleibt unveraendert. <br />
* Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefuegt
* und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false).
*
* @param pContent
* das anzuhaengende Objekt vom Typ ContentType
*/
public void append(ContentType pContent) {
if (pContent != null) { // Nichts tun, wenn es keine Inhalt gibt.
if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
this.insert(pContent);
} else { // Fall: An nicht-leere Liste anfuegen.
// Neuen Knoten erstellen.
ListNode newNode = new ListNode(pContent);
last.setNextNode(newNode);
last = newNode; // Letzten Knoten aktualisieren.
}
}
}
/**
* Falls es sich bei der Liste und pList um dasselbe Objekt handelt,
* pList null oder eine leere Liste ist, geschieht nichts.<br />
* Ansonsten wird die Liste pList an die aktuelle Liste angehaengt.
* Anschliessend wird pList eine leere Liste. Das aktuelle Objekt bleibt
* unveraendert. Insbesondere bleibt hasAccess identisch.
*
* @param pList
* die am Ende anzuhaengende Liste vom Typ List<ContentType>
*/
public void concat(List<ContentType> pList) {
if (pList != this && pList != null && !pList.isEmpty()) { // Nichts tun,
// wenn pList und this identisch, pList leer oder nicht existent.
if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
this.first = pList.first;
this.last = pList.last;
} else { // Fall: An nicht-leere Liste anfuegen.
this.last.setNextNode(pList.first);
this.last = pList.last;
}
// Liste pList loeschen.
pList.first = null;
pList.last = null;
pList.current = null;
}
}
/**
* Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess()
* == false), geschieht nichts.<br />
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
* aktuelle Objekt geloescht und das Objekt hinter dem geloeschten Objekt
* wird zum aktuellen Objekt. <br />
* Wird das Objekt, das am Ende der Liste steht, geloescht, gibt es kein
* aktuelles Objekt mehr.
*/
public void remove() {
// Nichts tun, wenn es kein aktuelle Element gibt oder die Liste leer ist.
if (this.hasAccess() && !this.isEmpty()) {
if (current == first) {
first = first.getNextNode();
} else {
ListNode previous = this.getPrevious(current);
if (current == last) {
last = previous;
}
previous.setNextNode(current.getNextNode());
}
ListNode temp = current.getNextNode();
current.setContentObject(null);
current.setNextNode(null);
current = temp;
//Beim loeschen des letzten Elements last auf null setzen.
if (this.isEmpty()) {
last = null;
}
}
}
/**
* Liefert den Vorgaengerknoten des Knotens pNode. Ist die Liste leer, pNode
* == null, pNode nicht in der Liste oder pNode der erste Knoten der Liste,
* wird null zurueckgegeben.
*
* @param pNode
* der Knoten, dessen Vorgaenger zurueckgegeben werden soll
* @return der Vorgaenger des Knotens pNode oder null, falls die Liste leer ist,
* pNode == null ist, pNode nicht in der Liste ist oder pNode der erste Knoten
* der Liste ist
*/
private ListNode getPrevious(ListNode pNode) {
if (pNode != null && pNode != first && !this.isEmpty()) {
ListNode temp = first;
while (temp != null && temp.getNextNode() != pNode) {
temp = temp.getNextNode();
}
return temp;
} else {
return null;
}
}
}

View File

@ -0,0 +1,29 @@
import schule.ngb.zm.*;
public class Attractor extends Mover {
private static final int G = 10;
private int mass = 0;
public Attractor( int x, int pY, int pMass ) {
this(x, pY, pMass, new Vector());
}
public Attractor( int x, int pY, int pMass, Vector pVelocity ) {
super(x, pY, pVelocity);
mass = pMass;
setFillColor(YELLOW);
}
public void attract( Mover pMover ) {
if( pMover != this ) {
Vector force = new Vector(this.x, this.y);
force.sub(pMover.getX(), pMover.getY()).scale(mass*G).limit(0, 50*G);
pMover.applyForce(force);
}
}
}

View File

@ -0,0 +1,34 @@
import schule.ngb.zm.Zeichenmaschine;
import java.util.List;
/**
* Beschreiben Sie hier die Klasse BluejTest.
*
* @author (Ihr Name)
* @version (eine Versionsnummer oder ein Datum)
*/
public class BluejTest extends Zeichenmaschine
{
public void setup() {
if( !IN_BLUEJ ) {
drawing.clear(schule.ngb.zm.Color.HGRED);
} else {
drawing.clear(schule.ngb.zm.Color.HGGREEN);
}
}
public void listClasses() {
// find all classes in classpath
List<String> allClasses = ClasspathInspector.getAllKnownClassNames();
System.out.printf("There are %s classes available in the classpath\n", allClasses.size());
for (String clazz : allClasses) {
if( clazz.contains("Boot") || clazz.contains("Main") ) {
System.out.printf("%s\n", clazz);
}
}
}
}

View File

@ -0,0 +1,283 @@
import java.io.File;
import java.io.FilenameFilter;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* Find classes in the classpath (reads JARs and classpath folders).
*
* @author P&aring;l Brattberg, brattberg@gmail.com
* @see http://gist.github.com/pal
*/
@SuppressWarnings("unchecked")
public class ClasspathInspector {
static boolean DEBUG = false;
public static List<String> getAllKnownClassNames() {
List<String> classNames = new ArrayList<String>();
List<File> classLocations = getClassLocationsForCurrentClasspath();
for (File file : classLocations) {
classNames.addAll(getClassNamesFromPath(file));
}
return classNames;
}
public static List<Class> getAllKnownClasses() {
List<Class> classFiles = new ArrayList<Class>();
List<File> classLocations = getClassLocationsForCurrentClasspath();
for (File file : classLocations) {
classFiles.addAll(getClassesFromPath(file));
}
return classFiles;
}
public static List<Class> getMatchingClasses(Class interfaceOrSuperclass) {
List<Class> matchingClasses = new ArrayList<Class>();
List<Class> classes = getAllKnownClasses();
log("checking %s classes", classes.size());
for (Class clazz : classes) {
if (interfaceOrSuperclass.isAssignableFrom(clazz)) {
matchingClasses.add(clazz);
log("class %s is assignable from %s", interfaceOrSuperclass, clazz);
}
}
return matchingClasses;
}
public static List<Class> getMatchingClasses(String validPackagePrefix, Class interfaceOrSuperclass) {
throw new IllegalStateException("Not yet implemented!");
}
public static List<Class> getMatchingClasses(String validPackagePrefix) {
throw new IllegalStateException("Not yet implemented!");
}
private static Collection<? extends Class> getClassesFromPath(File path) {
if (path.isDirectory()) {
return getClassesFromDirectory(path);
} else {
return getClassesFromJarFile(path);
}
}
private static Collection<String> getClassNamesFromPath(File path) {
if (path.isDirectory()) {
return getClassNamesFromDirectory(path);
} else {
return getClassNamesFromJarFile(path);
}
}
private static String fromFileToClassName(final String fileName) {
return fileName.substring(0, fileName.length() - 6).replaceAll("/|\\\\", "\\.");
}
private static List<Class> getClassesFromJarFile(File path) {
List<Class> classes = new ArrayList<Class>();
log("getClassesFromJarFile: Getting classes for " + path);
try {
if (path.canRead()) {
JarFile jar = new JarFile(path);
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements()) {
JarEntry entry = en.nextElement();
if (entry.getName().endsWith("class")) {
String className = fromFileToClassName(entry.getName());
log("\tgetClassesFromJarFile: found " + className);
Class claz = Class.forName(className);
classes.add(claz);
}
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to read classes from jar file: " + path, e);
}
return classes;
}
private static List<String> getClassNamesFromJarFile(File path) {
List<String> classes = new ArrayList<>();
log("getClassNamesFromJarFile: Getting classes for " + path);
try {
if (path.canRead()) {
JarFile jar = new JarFile(path);
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements()) {
JarEntry entry = en.nextElement();
if (entry.getName().endsWith("class")) {
String className = fromFileToClassName(entry.getName());
classes.add(className);
log("\tgetClassesFromJarFile: found " + className);
}
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to read classnames from jar file: " + path, e);
}
return classes;
}
private static List<Class> getClassesFromDirectory(File path) {
List<Class> classes = new ArrayList<Class>();
log("getClassesFromDirectory: Getting classes for " + path);
// get jar files from top-level directory
List<File> jarFiles = listFiles(path, new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
}, false);
for (File file : jarFiles) {
classes.addAll(getClassesFromJarFile(file));
}
// get all class-files
List<File> classFiles = listFiles(path, new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
}, true);
// List<URL> urlList = new ArrayList<URL>();
// List<String> classNameList = new ArrayList<String>();
int substringBeginIndex = path.getAbsolutePath().length() + 1;
for (File classfile : classFiles) {
String className = classfile.getAbsolutePath().substring(substringBeginIndex);
className = fromFileToClassName(className);
log("Found class %s in path %s: ", className, path);
try {
classes.add(Class.forName(className));
} catch (Throwable e) {
log("Couldn't create class %s. %s: ", className, e);
}
}
return classes;
}
private static List<String> getClassNamesFromDirectory(File path) {
List<String> classes = new ArrayList<>();
log("getClassNamesFromDirectory: Getting classes for " + path);
// get jar files from top-level directory
List<File> jarFiles = listFiles(path, new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
}, false);
for (File file : jarFiles) {
classes.addAll(getClassNamesFromJarFile(file));
}
// get all class-files
List<File> classFiles = listFiles(path, new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
}, true);
// List<URL> urlList = new ArrayList<URL>();
// List<String> classNameList = new ArrayList<String>();
int substringBeginIndex = path.getAbsolutePath().length() + 1;
for (File classfile : classFiles) {
String className = classfile.getAbsolutePath().substring(substringBeginIndex);
className = fromFileToClassName(className);
log("Found class %s in path %s: ", className, path);
classes.add(className);
}
return classes;
}
private static List<File> listFiles(File directory, FilenameFilter filter, boolean recurse) {
List<File> files = new ArrayList<File>();
File[] entries = directory.listFiles();
// Go over entries
for (File entry : entries) {
// If there is no filter or the filter accepts the
// file / directory, add it to the list
if (filter == null || filter.accept(directory, entry.getName())) {
files.add(entry);
}
// If the file is a directory and the recurse flag
// is set, recurse into the directory
if (recurse && entry.isDirectory()) {
files.addAll(listFiles(entry, filter, recurse));
}
}
// Return collection of files
return files;
}
public static List<File> getClassLocationsForCurrentClasspath() {
List<File> urls = new ArrayList<File>();
String javaClassPath = System.getProperty("java.class.path");
if (javaClassPath != null) {
for (String path : javaClassPath.split(File.pathSeparator)) {
urls.add(new File(path));
}
}
return urls;
}
// todo: this is only partial, probably
public static URL normalize(URL url) throws MalformedURLException {
String spec = url.getFile();
// get url base - remove everything after ".jar!/??" , if exists
final int i = spec.indexOf("!/");
if (i != -1) {
spec = spec.substring(0, spec.indexOf("!/"));
}
// uppercase windows drive
url = new URL(url, spec);
final String file = url.getFile();
final int i1 = file.indexOf(':');
if (i1 != -1) {
String drive = file.substring(i1 - 1, 2).toUpperCase();
url = new URL(url, file.substring(0, i1 - 1) + drive + file.substring(i1));
}
return url;
}
private static void log(String pattern, final Object... args) {
if (DEBUG)
System.out.printf(pattern + "\n", args);
}
public static void main(String[] args) {
// find all classes in classpath
List<Class> allClasses = ClasspathInspector.getAllKnownClasses();
System.out.printf("There are %s classes available in the classpath\n", allClasses.size());
// find all classes that implement/subclass an interface/superclass
List<Class> serializableClasses = ClasspathInspector.getMatchingClasses(Serializable.class);
for (Class clazz : serializableClasses) {
System.out.printf("%s is Serializable\n", clazz);
}
}
}

View File

@ -0,0 +1,40 @@
import java.util.LinkedList;
import schule.ngb.zm.*;
public class Gravity extends Zeichenmaschine {
private LinkedList<Mover> movers = new LinkedList<>();
private LinkedList<Attractor> attractors = new LinkedList<>();
public void setup(){
for( int i = 0; i < 10; i++ ) {
Mover m = new Mover(random(10, width-10), random(10, height-10));
movers.add(m);
shapes.add(m);
}
attractors.add(new Attractor(width/2, height/2, 10));
shapes.add(attractors.get(0));
}
public void update( double delta ) {
for( Attractor a: attractors ) {
for( Mover m: movers ) {
a.attract(m);
}
}
for( Mover m: movers ) {
m.update(delta);
}
shapes.clear();
}
public void draw() {
shapes.clear();
}
}

View File

@ -0,0 +1,38 @@
import schule.ngb.zm.*;
import schule.ngb.zm.formen.*;
public class Mover extends Circle implements Updatable {
private Vector velocity;
private Vector acceleration = new Vector();
public Mover( int x, int pY ) {
this(x, pY, new Vector());
}
public Mover( int x, int pY, Vector pVelocity ) {
super(x, pY, 10);
this.velocity = pVelocity.copy();
}
public void applyForce( Vector force ) {
acceleration.add(force);
}
public boolean isActive() {
return true;
}
public void update( double delta ) {
acceleration.scale(delta);
velocity.add(acceleration);
acceleration.scale(0.0);
this.x += velocity.x;
this.y += velocity.y;
}
}

View File

@ -0,0 +1,69 @@
#BlueJ package file
dependency1.from=BluejTest
dependency1.to=ClasspathInspector
dependency1.type=UsesDependency
dependency2.from=Gravity
dependency2.to=Mover
dependency2.type=UsesDependency
dependency3.from=Gravity
dependency3.to=Attractor
dependency3.type=UsesDependency
editor.fx.0.height=728
editor.fx.0.width=1037
editor.fx.0.x=95
editor.fx.0.y=53
objectbench.height=94
objectbench.width=776
package.divider.horizontal=0.6
package.divider.vertical=0.8305369127516778
package.editor.height=488
package.editor.width=661
package.editor.x=374
package.editor.y=158
package.frame.height=660
package.frame.width=800
package.numDependencies=3
package.numTargets=5
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=60
readme.name=@README
readme.width=48
readme.x=10
readme.y=10
target1.height=70
target1.name=Mover
target1.showInterface=false
target1.type=ClassTarget
target1.width=120
target1.x=320
target1.y=200
target2.height=70
target2.name=BluejTest
target2.showInterface=false
target2.type=ClassTarget
target2.width=120
target2.x=70
target2.y=10
target3.height=70
target3.name=Attractor
target3.showInterface=false
target3.type=ClassTarget
target3.width=120
target3.x=390
target3.y=350
target4.height=70
target4.name=ClasspathInspector
target4.showInterface=false
target4.type=ClassTarget
target4.width=130
target4.x=380
target4.y=30
target5.height=70
target5.name=Gravity
target5.showInterface=false
target5.type=ClassTarget
target5.width=120
target5.x=100
target5.y=300

View File

@ -1,114 +1,112 @@
package schule.ngb.zm;
import schule.ngb.zm.formen.Form;
import schule.ngb.zm.formen.Rechteck;
import schule.ngb.zm.formen.Rectangle;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class TestAttraction extends Zeichenfenster {
public class TestAttraction extends Zeichenmaschine {
public static void main(String[] args) {
new TestAttraction();
}
@Override
public void einstellungen() {
public void settings() {
setSize(800, 600);
setTitel("My test Window");
setTitle("My test Window");
//setFramesPerSecond(5);
s2dl = new Shape2DEbene();
hinzu(s2dl);
s2dl = new Shape2DLayer();
addLayer(s2dl);
}
Shape2DEbene s2dl;
Shape2DLayer s2dl;
Vektor posA, posB, velB, posC, velC;
Vector posA, posB, velB, posC, velC;
double massA = 500, massB = 1, massC = 4.3, G = 5.0;
Rechteck recht;
Rectangle recht;
@Override
public void vorbereiten() {
public void setup() {
//zeichnung.hide();
zeichnung.clear(200);
posA = new Vektor(0, 0);
posB = new Vektor(-100, -100);
velB = new Vektor(10, -10);
posC = new Vektor(200, 100);
velC = new Vektor(1, 14);
drawing.clear(200);
posA = new Vector(0, 0);
posB = new Vector(-100, -100);
velB = new Vector(10, -10);
posC = new Vector(200, 100);
velC = new Vector(1, 14);
zeichnung.translate(breite /2, hoehe /2);
zeichnung.shear(0.1, 0.5);
drawing.translate(width /2, height /2);
drawing.shear(0.1, 0.5);
recht = new Rechteck(50, 50, 150, 75);
recht.setFuellfarbe(200);
recht.setKonturFarbe(255, 0, 64);
recht.setKonturDicke(2.5);
recht.setKonturArt(Form.GESTRICHELT);
formen.anzeigen(recht);
recht = new Rectangle(50, 50, 150, 75);
recht.setFillColor(200);
recht.setStrokeColor(255, 0, 64);
recht.setStrokeWeight(2.5);
recht.setStrokeType(DASHED);
shapes.add(recht);
zeichnung.verstecken();
drawing.hide();
//schule.ngb.zm.formen.verstecken();
s2dl.setColor(64,200,128);
s2dl.setFillColor(64,200,128);
s2dl.add(new Rectangle2D.Double(100, 100, 120, 80));
}
public void zeichnen() {
zeichnung.setStrokeColor(255);
zeichnung.setStrokeWeight(4.0);
zeichnung.setKonturArt(GESTRICHELT);
zeichnung.clear(33, 33, 33, 100);
public void draw() {
drawing.setStrokeColor(255);
drawing.setStrokeWeight(4.0);
drawing.setStrokeType(DASHED);
drawing.clear(33, 33, 33, 100);
zeichnung.setColor(Color.ORANGE);
zeichnung.pie(posA.x, posA.y, 80, 30, 60);
zeichnung.setColor(Color.YELLOW);
zeichnung.circle(posA.x, posA.y, 60);
drawing.setColor(Color.ORANGE);
drawing.pie(posA.x, posA.y, 80, 30, 60);
drawing.setColor(Color.YELLOW);
drawing.circle(posA.x, posA.y, 60);
Vektor acc = acceleration(posA, posB, massA, massB);
velB.addieren(acc);
posB.addieren(velB);
Vector acc = acceleration(posA, posB, massA, massB);
velB.add(acc);
posB.add(velB);
zeichnung.setColor(Color.BLUE);
zeichnung.circle(posB.x, posB.y, 20);
drawing.setColor(Color.BLUE);
drawing.circle(posB.x, posB.y, 20);
acc = acceleration(posA, posC, massA, massC);
velC.addieren(acc);
posC.addieren(velC);
velC.add(acc);
posC.add(velC);
zeichnung.setColor(Color.GREEN);
zeichnung.circle(posC.x, posC.y, 20);
drawing.setColor(Color.GREEN);
drawing.circle(posC.x, posC.y, 20);
zeichnung.rotate(1);
drawing.rotate(1);
formen.leeren();
shapes.clear();
double x = recht.getX();
x = (x+100*delta)% breite;
x = (x+100*delta)% width;
recht.setX(x);
}
Vektor acceleration(Vektor a, Vektor b, double ma, double mb ) {
Vektor acc = Vektor.subtrahieren(a, b);
double draw = (G*ma*mb)/acc.laengeQuad();
acc.setLaenge(draw*delta);
acc.beschraenken(3, 30);
Vector acceleration( Vector a, Vector b, double ma, double mb ) {
Vector acc = Vector.sub(a, b);
double draw = (G*ma*mb)/acc.lenSq();
acc.setLen(draw*delta);
acc.limit(3, 30);
return acc;
}
public void mouseDragged() {
zeichnung.translate(mausX - lmausX, mausY - lmausY);
drawing.translate(mouseX - pmouseX, mouseY - pmouseY);
}
boolean zoom = true;
public void mouseClicked() {
//canvas.translateToCanvas(mouseX-width/2.0, mouseY-height/2.0);
if( zoom ) {
zeichnung.scale(2.0);
drawing.scale(2.0);
} else {
zeichnung.scale(.5);
drawing.scale(.5);
}
zoom = !zoom;
}

View File

@ -0,0 +1,145 @@
package schule.ngb.zm;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestColor {
@Test
public void colors() {
Color c;
c = new Color();
assertEquals(0, c.getRed());
assertEquals(0, c.getGreen());
assertEquals(0, c.getBlue());
assertEquals(255, c.getAlpha());
c = Color.BLUE;
assertEquals(0, c.getRed());
assertEquals(0, c.getGreen());
assertEquals(255, c.getBlue());
assertEquals(255, c.getAlpha());
c = new Color(50, 133, 64, 33);
assertEquals(50, c.getRed());
assertEquals(133, c.getGreen());
assertEquals(64, c.getBlue());
assertEquals(33, c.getAlpha());
c = new Color(255, 0, 0);
assertEquals(Color.RED, c);
c = new Color(33, 50);
assertEquals(33, c.getRed());
assertEquals(33, c.getGreen());
assertEquals(33, c.getBlue());
assertEquals(50, c.getAlpha());
}
@Test
public void parseColors() {
Color c;
c = Color.parseRGB(0x00FF00FF);
assertEquals(0x00FF00FF, c.getRGBA());
assertEquals(255, c.getRed());
assertEquals(0, c.getGreen());
assertEquals(255, c.getBlue());
assertEquals(0, c.getAlpha());
c = Color.parseRGB(0x33FF3333);
assertEquals(0x33FF3333, c.getRGBA());
assertEquals(255, c.getRed());
assertEquals(51, c.getGreen());
assertEquals(51, c.getBlue());
assertEquals(51, c.getAlpha());
c = Color.parseHexcode("FF00FF");
assertEquals(0xFFFF00FF, c.getRGBA());
assertEquals(255, c.getRed());
assertEquals(0, c.getGreen());
assertEquals(255, c.getBlue());
assertEquals(255, c.getAlpha());
c = Color.parseHexcode("#FF00FF00");
assertEquals(0x00FF00FF, c.getRGBA());
assertEquals(255, c.getRed());
assertEquals(0, c.getGreen());
assertEquals(255, c.getBlue());
assertEquals(0, c.getAlpha());
c = Color.parseHexcode("#333");
assertEquals(0xFF333333, c.getRGBA());
assertEquals(51, c.getRed());
assertEquals(51, c.getGreen());
assertEquals(51, c.getBlue());
assertEquals(255, c.getAlpha());
c = Color.parseHexcode("#33FF0033");
assertEquals(0x3333FF00, c.getRGBA());
assertEquals(51, c.getRed());
assertEquals(255, c.getGreen());
assertEquals(0, c.getBlue());
assertEquals(51, c.getAlpha());
}
@Test
public void hsl() {
Color c;
float[] hsl;
c = Color.RED;
hsl = Color.RGBtoHSL(c.getRGBA(), null);
assertArrayEquals(new float[]{0f,1f,.5f}, hsl, 0.0001f);
c = new Color(255, 33, 64);
hsl = Color.RGBtoHSL(c.getRGBA(), null);
assertEquals(352, hsl[0], 1.0f);
assertEquals(1.0f, hsl[1], .0001f);
assertEquals(.5647f, hsl[2], .0001f);
}
public static void main( String[] args ) {
new ColorPalette();
}
static class ColorPalette extends Zeichenmaschine {
public static final int SIZE = 10, COLORS = 16;
public void setup() {
setSize(SIZE*COLORS, SIZE*COLORS);
setTitle("Colors");
drawing.noStroke();
drawing.setAnchor(NORTHWEST);
int steps = (int) (255.0/COLORS);
Color c;
for( int i = 0; i < COLORS; i++ ) {
for( int j = 0; j < COLORS; j++ ) {
c = new Color(i * steps, j * steps, (i+j)/2 * steps);
drawing.setColor(c);
drawing.rect(i*SIZE, j*SIZE, SIZE, SIZE);
}
}
}
public void draw() {
Color c = Color.HGGREEN;
drawing.setColor(c);
drawing.rect(0, 0, width/2, height);
for( int p = 10; p < 100; p += 10 ) {
drawing.setColor(c.brighter(p));
drawing.rect(width / 2, 0, width / 2, height / 2);
drawing.setColor(c.darker(p));
drawing.rect(width / 2, height / 2, width / 2, height / 2);
delay(1000);
}
}
}
}

View File

@ -0,0 +1,73 @@
package schule.ngb.zm;
import schule.ngb.zm.util.List;
public class TestDrawing extends Zeichenmaschine {
private final double w = 100, h = 50;
private double xa = 50, ya = 50;
private double x2 = 200, y2 = 50;
int frames = 0;
long start = 0;
public static void main( String[] args ) {
new TestDrawing();
}
@Override
public void setup() {
drawing.setFont("AvenirNext-Medium", 14);
drawing.setAnchor(NORTHWEST);
start = System.currentTimeMillis();
}
@Override
public void update( double delta ) {
ya = (ya+1)%350;
}
@Override
public void draw() {
long ms = System.currentTimeMillis();
drawing.clear();
// x2 = mouseX;
// y2 = mouseY;
drawing.resetStroke();
drawing.rect(xa, ya, w, h);
//drawing.image("WitchCraftIcons_122_t.PNG", width/2, height/2, .5, CENTER);
for( int i = 0; i < 4; i++ ) {
//delay(1000);
drawing.resetStroke();
drawing.rect(x2 + i*10, y2 + i * 75, w, h);
connect(xa + w, ya + h / 2.0, x2 + i*10, y2 + i * 75 + h / 2.0);
drawing.text("Rect " + i, x2 + i*10 + w / 2.0, y2 + i * 75 + h / 2.0, CENTER);
}
if( (System.currentTimeMillis()-start) >= 1000 ) {
System.out.printf("FPS: %d\n", frames);
frames = 0;
start = System.currentTimeMillis();
} else {
frames += 1;
}
}
private void connect( double x1, double y1, double x2, double y2 ) {
double midx = (x1 + x2) / 2.0;
drawing.setStrokeType(DASHED);
drawing.setStrokeWeight(2.4);
drawing.curve(x1, y1, midx, y1, midx, y2, x2, y2);
//drawing.curve(x1, y1, x2, y1, x1, y2, x2, y2);
}
}

View File

@ -1,57 +1,104 @@
package schule.ngb.zm;
import schule.ngb.zm.formen.*;
import schule.ngb.zm.formen.Point;
import schule.ngb.zm.formen.Polygon;
import schule.ngb.zm.formen.Rectangle;
import schule.ngb.zm.formen.Shape;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Random;
public class TestFormen extends Zeichenfenster {
public class TestFormen extends Zeichenmaschine {
Random rand = new Random();
public static void main( String[] args ) {
new TestFormen();
}
Kurve k;
@Override
public void vorbereiten() {
public void setup() {
setSize(400, 400);
k = new Kurve(50, 50, 100, 50, 100, 100,150, 100);
//formen.anzeigen(new Kurve(50, 50, 100, 50, 150, 100));
formen.anzeigen(k);
add(new Rectangle(20, 10, 40, 20));
add(new Ellipse(40, 50, 40, 20));
add(new Circle(40, 80, 10));
k.verschiebeNach(200, 200);
k.skalieren(1.1);
add(new Line(40, 100, 100, 40));
add(new Arrow(200, 200, 105, 45));
showDot(k.getStartpunkt());
showDot(k.getKontrollpunkt1());
showDot(k.getKontrollpunkt2());
showDot(k.getEndpunkt());
shapes.add(new Point(200, 200));
add(new Rhombus(40, 200, 50, 120));
add(new Kite(40, 200, 50, 120, .75));
add(new Kite(40, 200, 50, 120, .25));
add(new RoundedRectangle(20, 300, 100, 60, 30));
add(new Arc(200, 200, 60, 90, 120));
add(new Polygon(250, 40, 300, 55, 321, 83, 200, 300));
shapes.add(new Point(250, 40));
shapes.add(new Point(300, 55));
shapes.add(new Point(321, 83));
shapes.add(new Point(200, 300));
add(new Triangle(300, 55, 355, 75, 345, 25));
add(new Quad(300, 55, 355, 75, 345, 25, 300, 10));
add(new Curve(50, 50, 350, 50, 350, 350));
add(new Curve(50, 50, 50, 350, 350, 50, 350, 350));
shapes.add(new Picture(300, 300, "WitchCraftIcons_122_t.PNG"));
add(new Text(200, 40, "Shapes 😊"));
}
@Override
public void aktualisieren( double delta ) {
public void update( double delta ) {
}
@Override
public void zeichnen() {
formen.leeren();
public void mouseClicked() {
for( Shape s : shapes.getShapes() ) {
randomizeShape(s);
s.move(10, 10);
}
}
private void add( Shape s ) {
shapes.add(randomizeShape(s));
}
private Shape randomizeShape( Shape s ) {
if( !(s instanceof Arc) && !(s instanceof Curve) && !(s instanceof Line) && !(s instanceof Arrow) ) {
s.setFillColor(randomColor());
}
s.setStrokeColor(randomColor());
s.setStrokeWeight(random(.75, 2.25));
if( randomBool(20) ) {
s.setStrokeType(DASHED);
} else {
s.setStrokeType(SOLID);
}
//s.moveTo(random(20, 380), random(20, 380));
return s;
}
private void showDot( Point2D p ) {
showDot(p.getX(), p.getY(), randomColor());
}
private void showDot( double x, double y, Color clr ) {
Punkt p = new Punkt(x, y);
p.setFuellfarbe(clr);
p.setKonturFarbe(clr);
formen.anzeigen(p);
}
Random rand = new Random();
private void showDot( double x, double y, Color clr ) {
Point p = new Point(x, y);
p.setFillColor(clr);
p.setStrokeColor(clr);
shapes.add(p);
}
private Color randomColor() {
return new Color(

View File

@ -0,0 +1,5 @@
package schule.ngb.zm;
public class TestVector {
}