Vereinheitlichung der APIs für Füllungen und Konturen

This commit is contained in:
ngb
2022-07-31 09:59:36 +02:00
parent b0353c53a0
commit 6126ed3c15
7 changed files with 906 additions and 454 deletions

View File

@@ -0,0 +1,239 @@
package schule.ngb.zm;
import schule.ngb.zm.shapes.Fillable;
import schule.ngb.zm.shapes.Strokeable;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
/**
* Basisimplementierung der {@link Strokeable} und {@link Fillable} APIs.
*
* Die Klasse bietet eine Grundlage zur Implementierung eigener Zeichenobjekte,
* die eine Füllung und eine Konturlinie haben können.
*/
public abstract class BasicDrawable extends Constants implements Strokeable, Fillable {
/**
* Ob das Objekt gezeichnet werden soll.
*/
protected boolean visible = true;
/**
* Aktuelle Farbe der Konturlinie oder {@code null}, wenn das Objekt ohne
* Kontur dargestellt werden soll.
*/
protected schule.ngb.zm.Color strokeColor = DEFAULT_STROKECOLOR;
/**
* Die Dicke der Konturlinie. Wird nicht kleiner als 0.
*/
protected double strokeWeight = DEFAULT_STROKEWEIGHT;
/**
* Die Art der Konturlinie.
*/
protected Options.StrokeType strokeType = SOLID;
/**
* Cache für den aktuellen {@code Stroke} der Kontur. Wird nach Änderung
* einer der Kontureigenschaften auf {@code null} gesetzt und beim nächsten
* Zeichnen neu erstellt.
*/
protected Stroke stroke = null;
/**
* Die aktuelle Füllfarbe der Form oder {@code null}, wenn das Objekt nicht
* gefüllt werden soll.
*/
protected Color fillColor = DEFAULT_FILLCOLOR;
/**
* Der aktuelle Farbverlauf des Objektes oder {@code null}, wenn es keinen
* Farbverlauf besitzt.
*/
protected GradientPaint fill = null;
// Implementierung Drawable Interface
/**
* Ob das Objekt angezeigt bzw. gezeichnet werden soll.
*
* @return {@code true}, wenn das Objekt angezeigt werden soll,
* {@code false} sonst.
*/
public boolean isVisible() {
return visible;
}
/**
* Versteckt das Objekt.
*/
public void hide() {
visible = false;
}
/**
* Zeigt das Objekt an.
*/
public void show() {
visible = true;
}
/**
* Versteckt da Objekt, wenn es derzeit angezeigt wird und zeigt es
* andernfalls an.
*/
public void toggle() {
visible = !visible;
}
public abstract void draw( Graphics2D graphics );
// Implementierung Fillable Interface
/**
* {@inheritDoc}
*/
@Override
public void setFill( Paint fill ) {
if( fill instanceof Color ) {
this.setFillColor((Color) fill);
} else if( fill instanceof GradientPaint ) {
this.fillColor = null;
this.fill = (GradientPaint) fill;
}
}
/**
* {@inheritDoc}
*/
@Override
public Paint getFill() {
if( fill != null ) {
return fill;
} else if( fillColor != null && fillColor.getAlpha() > 0 ) {
return fillColor;
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasFillColor() {
return fillColor != null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasGradient() {
return fill != null;
}
/**
* {@inheritDoc}
*/
@Override
public Color getFillColor() {
return fillColor;
}
/**
* {@inheritDoc}
*/
@Override
public void setFillColor( Color color ) {
fillColor = color;
fill = null;
}
/**
* {@inheritDoc}
*/
@Override
public GradientPaint getGradient() {
return fill;
}
// Implementierung Strokeable Interface
/**
* {@inheritDoc}
*/
@Override
public void setStroke( Stroke stroke ) {
this.stroke = stroke;
}
/**
* {@inheritDoc}
*/
@Override
public Stroke getStroke() {
if( stroke == null ) {
stroke = Strokeable.createStroke(strokeType, strokeWeight);
}
return stroke;
}
/**
* {@inheritDoc}
*/
@Override
public Color getStrokeColor() {
return strokeColor;
}
/**
* {@inheritDoc}
*/
@Override
public void setStrokeColor( Color color ) {
strokeColor = color;
}
/**
* {@inheritDoc}
*/
@Override
public double getStrokeWeight() {
return strokeWeight;
}
/**
* {@inheritDoc}
*/
@Override
public void setStrokeWeight( double weight ) {
strokeWeight = weight;
this.stroke = null;
}
/**
* {@inheritDoc}
*/
@Override
public Options.StrokeType getStrokeType() {
return strokeType;
}
/**
* {@inheritDoc}
*/
@Override
public void setStrokeType( Options.StrokeType type ) {
strokeType = type;
this.stroke = null;
}
}

View File

@@ -3,13 +3,12 @@ package schule.ngb.zm.layers;
import schule.ngb.zm.Color; import schule.ngb.zm.Color;
import schule.ngb.zm.Layer; import schule.ngb.zm.Layer;
import schule.ngb.zm.Options; import schule.ngb.zm.Options;
import schule.ngb.zm.shapes.Fillable;
import schule.ngb.zm.shapes.Strokeable;
import schule.ngb.zm.shapes.Text; import schule.ngb.zm.shapes.Text;
import schule.ngb.zm.util.io.ImageLoader; import schule.ngb.zm.util.io.ImageLoader;
import java.awt.Font; import java.awt.*;
import java.awt.FontMetrics;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.*; import java.awt.geom.*;
import java.util.Stack; import java.util.Stack;
@@ -20,7 +19,7 @@ import java.util.Stack;
* {@link schule.ngb.zm.Zeichenmaschine}. * {@link schule.ngb.zm.Zeichenmaschine}.
*/ */
@SuppressWarnings( "unused" ) @SuppressWarnings( "unused" )
public class DrawingLayer extends Layer { public class DrawingLayer extends Layer implements Strokeable, Fillable {
/** /**
* Wiederverwendbarer Speicher für eine Linie. * Wiederverwendbarer Speicher für eine Linie.
@@ -199,6 +198,16 @@ public class DrawingLayer extends Layer {
shapeDelegate.resetFill(); shapeDelegate.resetFill();
} }
@Override
public void setFill( Paint fill ) {
shapeDelegate.setFill(fill);
}
@Override
public Paint getFill() {
return shapeDelegate.getFill();
}
/** /**
* Setzt die Füllung auf einen linearen Farbverlauf, der am Punkt * Setzt die Füllung auf einen linearen Farbverlauf, der am Punkt
* ({@code fromX}, {@code fromY}) mit der Farbe {@code from} startet und am * ({@code fromX}, {@code fromY}) mit der Farbe {@code from} startet und am
@@ -232,6 +241,18 @@ public class DrawingLayer extends Layer {
shapeDelegate.setGradient(centerX, centerY, radius, from, to); shapeDelegate.setGradient(centerX, centerY, radius, from, to);
} }
@Override
public void setGradient( Color from, Color to, Options.Direction dir ) {
Point2D.Double anchorPoint = schule.ngb.zm.shapes.Shape.getAnchorPoint(getWidth(), getHeight(), dir);
Point2D.Double inversePoint = schule.ngb.zm.shapes.Shape.getAnchorPoint(getWidth(), getHeight(), dir.inverse());
shapeDelegate.setGradient(inversePoint.x, inversePoint.y, from, anchorPoint.x, anchorPoint.y, to);
}
@Override
public void setGradient( Color from, Color to ) {
shapeDelegate.setGradient(getWidth()/2.0, getHeight()/2.0, min(getWidth(), getHeight())/2.0, from, to);
}
/** /**
* Entfernt den Farbverlauf von der Form. * Entfernt den Farbverlauf von der Form.
*/ */
@@ -239,6 +260,11 @@ public class DrawingLayer extends Layer {
shapeDelegate.noGradient(); shapeDelegate.noGradient();
} }
@Override
public void setStroke( Stroke stroke ) {
shapeDelegate.setStroke(stroke);
}
/** /**
* Gibt die aktuelle Farbe der Konturlinie zurück. * Gibt die aktuelle Farbe der Konturlinie zurück.
* *
@@ -386,6 +412,11 @@ public class DrawingLayer extends Layer {
shapeDelegate.setStrokeType(type); shapeDelegate.setStrokeType(type);
} }
@Override
public Stroke getStroke() {
return shapeDelegate.getStroke();
}
public void setAnchor( Options.Direction anchor ) { public void setAnchor( Options.Direction anchor ) {
shapeDelegate.setAnchor(anchor); shapeDelegate.setAnchor(anchor);
} }
@@ -579,8 +610,8 @@ public class DrawingLayer extends Layer {
} }
protected void fillShape( Shape shape ) { protected void fillShape( Shape shape ) {
if( shapeDelegate.getPaint() != null ) { if( shapeDelegate.getFill() != null ) {
drawing.setPaint(shapeDelegate.getPaint()); drawing.setPaint(shapeDelegate.getFill());
drawing.fill(shape); drawing.fill(shape);
} }
} }
@@ -732,6 +763,8 @@ public class DrawingLayer extends Layer {
public void resetStyle() { public void resetStyle() {
Text newDelegate = new Text(0, 0, ""); Text newDelegate = new Text(0, 0, "");
newDelegate.setFillColor(DEFAULT_FILLCOLOR);
newDelegate.setStrokeColor(DEFAULT_STROKECOLOR);
if( shapeDelegate != null ) { if( shapeDelegate != null ) {
newDelegate.setAnchor(shapeDelegate.getAnchor()); newDelegate.setAnchor(shapeDelegate.getAnchor());
} }

View File

@@ -1,12 +1,15 @@
package schule.ngb.zm.layers; package schule.ngb.zm.layers;
import schule.ngb.zm.Color; import schule.ngb.zm.*;
import schule.ngb.zm.Layer; import schule.ngb.zm.shapes.Fillable;
import schule.ngb.zm.Options; import schule.ngb.zm.shapes.Rectangle;
import schule.ngb.zm.Vector; import schule.ngb.zm.shapes.Shape;
import schule.ngb.zm.shapes.FilledShape; import schule.ngb.zm.shapes.Strokeable;
import java.awt.GradientPaint;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.ArrayList; import java.util.ArrayList;
@@ -14,7 +17,7 @@ import java.util.List;
import java.util.Stack; import java.util.Stack;
@SuppressWarnings( "unused" ) @SuppressWarnings( "unused" )
public class TurtleLayer extends Layer { public class TurtleLayer extends Layer implements Strokeable, Fillable {
// Rotating by the clock // Rotating by the clock
public static final int H1 = 30; public static final int H1 = 30;
@@ -119,7 +122,20 @@ public class TurtleLayer extends Layer {
} }
} }
// Begin of delegate methods (auto-generated) // begin of delegate methods (auto-generated)
@Override
public boolean isVisible() {
return mainTurtle.isVisible();
}
public void beginPath() {
mainTurtle.beginPath();
}
public void closePath() {
mainTurtle.closePath();
}
public void fill() { public void fill() {
mainTurtle.fill(); mainTurtle.fill();
@@ -177,101 +193,194 @@ public class TurtleLayer extends Layer {
mainTurtle.moveTo(x, y); mainTurtle.moveTo(x, y);
} }
public Color getFillColor() { @Override
return mainTurtle.getFillColor(); public void setFill( Paint fill ) {
mainTurtle.setFill(fill);
} }
@Override
public Paint getFill() {
return mainTurtle.getFill();
}
@Override
public void setFillColor( Color color ) { public void setFillColor( Color color ) {
mainTurtle.setFillColor(color); mainTurtle.setFillColor(color);
} }
public void setFillColor( int gray ) { @Override
mainTurtle.setFillColor(gray); public Color getFillColor() {
} return mainTurtle.getFillColor();
public void noFill() {
mainTurtle.noFill();
}
public void setFillColor( int gray, int alpha ) {
mainTurtle.setFillColor(gray, alpha);
}
public void setFillColor( int red, int green, int blue ) {
mainTurtle.setFillColor(red, green, blue);
}
public void setFillColor( int red, int green, int blue, int alpha ) {
mainTurtle.setFillColor(red, green, blue, alpha);
}
public void resetFill() {
mainTurtle.resetFill();
}
public Color getStrokeColor() {
return mainTurtle.getStrokeColor();
} }
@Override
public void setStrokeColor( Color color ) { public void setStrokeColor( Color color ) {
mainTurtle.setStrokeColor(color); mainTurtle.setStrokeColor(color);
} }
public void setStrokeColor( int gray ) { @Override
mainTurtle.setStrokeColor(gray);
}
public void noStroke() {
mainTurtle.noStroke();
}
public void setStrokeColor( int gray, int alpha ) {
mainTurtle.setStrokeColor(gray, alpha);
}
public void setStrokeColor( int red, int green, int blue ) {
mainTurtle.setStrokeColor(red, green, blue);
}
public void setStrokeColor( int red, int green, int blue, int alpha ) {
mainTurtle.setStrokeColor(red, green, blue, alpha);
}
public double getStrokeWeight() {
return mainTurtle.getStrokeWeight();
}
public void setStrokeWeight( double weight ) { public void setStrokeWeight( double weight ) {
mainTurtle.setStrokeWeight(weight); mainTurtle.setStrokeWeight(weight);
} }
@Override
public Options.StrokeType getStrokeType() { public Options.StrokeType getStrokeType() {
return mainTurtle.getStrokeType(); return mainTurtle.getStrokeType();
} }
@Override
public void setStrokeType( Options.StrokeType type ) { public void setStrokeType( Options.StrokeType type ) {
mainTurtle.setStrokeType(type); mainTurtle.setStrokeType(type);
} }
@Override
public void setGradient( Color from, Color to, Options.Direction dir ) {
mainTurtle.setGradient(from, to, dir);
}
@Override
public void setGradient( Color from, Color to ) {
mainTurtle.setGradient(from, to);
}
@Override
public boolean hasFill() {
return mainTurtle.hasFill();
}
@Override
public boolean hasFillColor() {
return mainTurtle.hasFillColor();
}
@Override
public boolean hasGradient() {
return mainTurtle.hasGradient();
}
@Override
public void setFillColor( Color color, int alpha ) {
mainTurtle.setFillColor(color, alpha);
}
@Override
public void setFillColor( int gray ) {
mainTurtle.setFillColor(gray);
}
@Override
public void setFillColor( int gray, int alpha ) {
mainTurtle.setFillColor(gray, alpha);
}
@Override
public void setFillColor( int red, int green, int blue ) {
mainTurtle.setFillColor(red, green, blue);
}
@Override
public void setFillColor( int red, int green, int blue, int alpha ) {
mainTurtle.setFillColor(red, green, blue, alpha);
}
@Override
public void noFill() {
mainTurtle.noFill();
}
@Override
public void resetFill() {
mainTurtle.resetFill();
}
@Override
public GradientPaint getGradient() {
return mainTurtle.getGradient();
}
@Override
public void setGradient( double fromX, double fromY, Color from, double toX, double toY, Color to ) {
mainTurtle.setGradient(fromX, fromY, from, toX, toY, to);
}
@Override
public void setGradient( double centerX, double centerY, double radius, Color from, Color to ) {
mainTurtle.setGradient(centerX, centerY, radius, from, to);
}
@Override
public void noGradient() {
mainTurtle.noGradient();
}
@Override
public void setStroke( Stroke stroke ) {
mainTurtle.setStroke(stroke);
}
@Override
public Stroke getStroke() {
return mainTurtle.getStroke();
}
@Override
public boolean hasStroke() {
return mainTurtle.hasStroke();
}
@Override
public Color getStrokeColor() {
return mainTurtle.getStrokeColor();
}
@Override
public void setStrokeColor( Color color, int alpha ) {
mainTurtle.setStrokeColor(color, alpha);
}
@Override
public void setStrokeColor( int gray ) {
mainTurtle.setStrokeColor(gray);
}
@Override
public void setStrokeColor( int gray, int alpha ) {
mainTurtle.setStrokeColor(gray, alpha);
}
@Override
public void setStrokeColor( int red, int green, int blue ) {
mainTurtle.setStrokeColor(red, green, blue);
}
@Override
public void setStrokeColor( int red, int green, int blue, int alpha ) {
mainTurtle.setStrokeColor(red, green, blue, alpha);
}
@Override
public void noStroke() {
mainTurtle.noStroke();
}
@Override
public void resetStroke() { public void resetStroke() {
mainTurtle.resetStroke(); mainTurtle.resetStroke();
} }
public void beginPath() { @Override
mainTurtle.beginPath(); public double getStrokeWeight() {
return mainTurtle.getStrokeWeight();
} }
public void closePath() {
mainTurtle.closePath();
}
// End of delegate methods (auto-generated) // end of delegate methods (auto-generated)
/** /**
* Die Turtle der Zeichenmaschine. * Die Turtle der Zeichenmaschine.
*/ */
public class Turtle extends FilledShape { public class Turtle extends BasicDrawable {
private static final int DEFAULT_SIZE = 12; private static final int DEFAULT_SIZE = 12;
@@ -287,9 +396,18 @@ public class TurtleLayer extends Layer {
boolean pathOpen = false; boolean pathOpen = false;
/**
* Path-Objekt für die Darstellung der Turtle.
*/
Path2D.Double turtlePath;
Turtle() { Turtle() {
} }
public boolean isVisible() {
return visible;
}
public void beginPath() { public void beginPath() {
pathOpen = false; pathOpen = false;
addPosToPath(); addPosToPath();
@@ -317,34 +435,29 @@ public class TurtleLayer extends Layer {
public void fill() { public void fill() {
closePath(); closePath();
if( fillColor != null && fillColor.getAlpha() > 0 ) { if( hasFill() ) {
drawing.setColor(fillColor.getJavaColor()); drawing.setPaint(getFill());
drawing.fill(path); drawing.fill(path);
} }
} }
public boolean isVisible() {
return visible;
}
@Override @Override
public void draw( Graphics2D graphics ) { public void draw( Graphics2D graphics ) {
/*Shape shape = new RoundRectangle2D.Double( if( turtlePath == null ) {
-12, -5, 16, 10, 5, 3 turtlePath = new Path2D.Double();
);*/ path.moveTo(DEFAULT_SIZE, 0);
Path2D path = new Path2D.Double(); path.lineTo(-DEFAULT_SIZE, -DEFAULT_SIZE / 2.0);
path.moveTo(DEFAULT_SIZE, 0); path.lineTo(-DEFAULT_SIZE, DEFAULT_SIZE / 2.0);
path.lineTo(-DEFAULT_SIZE, -DEFAULT_SIZE / 2.0); path.lineTo(DEFAULT_SIZE, 0);
path.lineTo(-DEFAULT_SIZE, DEFAULT_SIZE / 2.0); }
path.lineTo(DEFAULT_SIZE, 0);
AffineTransform verzerrung = new AffineTransform(); AffineTransform verzerrung = new AffineTransform();
verzerrung.translate(position.x, position.y); verzerrung.translate(position.x, position.y);
verzerrung.rotate(Math.toRadians(direction.angle())); verzerrung.rotate(Math.toRadians(direction.angle()));
java.awt.Shape shape = verzerrung.createTransformedShape(path); java.awt.Shape shape = verzerrung.createTransformedShape(turtlePath);
if( strokeColor != null ) { if( hasStroke() ) {
graphics.setColor(strokeColor.getJavaColor()); graphics.setColor(strokeColor.getJavaColor());
} else { } else {
graphics.setColor(DEFAULT_STROKECOLOR.getJavaColor()); graphics.setColor(DEFAULT_STROKECOLOR.getJavaColor());
@@ -365,7 +478,7 @@ public class TurtleLayer extends Layer {
Vector positionStart = position.copy(); Vector positionStart = position.copy();
position.add(Vector.setLength(direction, dist)); position.add(Vector.setLength(direction, dist));
if( penDown && strokeColor != null ) { if( penDown && hasStroke() ) {
drawing.setColor(strokeColor.getJavaColor()); drawing.setColor(strokeColor.getJavaColor());
drawing.setStroke(getStroke()); drawing.setStroke(getStroke());
drawing.drawLine((int) positionStart.x, (int) positionStart.y, (int) position.x, (int) position.y); drawing.drawLine((int) positionStart.x, (int) positionStart.y, (int) position.x, (int) position.y);
@@ -418,7 +531,7 @@ public class TurtleLayer extends Layer {
position.x = x; position.x = x;
position.y = y; position.y = y;
if( penDown && strokeColor != null ) { if( penDown && hasStroke() ) {
drawing.setColor(strokeColor.getJavaColor()); drawing.setColor(strokeColor.getJavaColor());
drawing.setStroke(getStroke()); drawing.setStroke(getStroke());
drawing.drawLine((int) x, (int) y, (int) position.x, (int) position.y); drawing.drawLine((int) x, (int) y, (int) position.x, (int) position.y);

View File

@@ -0,0 +1,282 @@
package schule.ngb.zm.shapes;
import schule.ngb.zm.Color;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Drawable;
import schule.ngb.zm.Options;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
/**
* {@link Drawable} Klassen, die mit einer Füllung versehen werden können.
* <p>
* Das {@code Fillable} Interface dient hauptsächlich zur Vereinheitlichung der
* API für Füllungen. Durch Implementation wird sichergestellt, dass alle
* Objekte, die eine Füllung haben können, dieselben Methoden zur Verfügung
* stellen. Wenn eine {@link Shape} eine
* {@link Fillable#setFillColor(Color, int)} Methode hat, dann sollte auch eine
* {@link schule.ngb.zm.layers.TurtleLayer.Turtle} dieselbe Methode anbieten. Im
* Einzelfall kann es sinnvoll sein, weitere Methoden für Füllungen zur
* Verfügung zu stellen. Allerdings sollte davon nach Möglichkeit zugunsten
* einer einheitlichen API abgesehen werden.
* <p>
* Das Äquivalent für Konturlinien stellt {@link Strokeable} dar.
* <p>
* Im einfachsten Fall reicht es {@link #setFill(Paint)} und {@link #getFill()}
* zu implementieren. Die anderen Methoden besitzen Standardimplementierungen,
* die sich auf die beiden Methoden beziehen. Allerdings ist es in vielen Fällen
* sinnvoll, einige der Methoden gezielt zu überschreiben, um sie an spezifische
* Situationen anzupassen.
*/
public interface Fillable extends Drawable {
/**
* Setzt die Füllung direkt auf das angegebene {@code Paint}-Objekt.
*
* @param fill Die neue Füllung.
*/
void setFill( Paint fill );
/**
* Gibt die aktuell gesetzte Füllung zurück.
* <p>
* Die Art der Füllung kann anhand der Abfragen {@link #hasFillColor()} und
* {@link #hasGradient()} ermittelt werden.
*
* @return Die aktuelle Füllung.
*/
Paint getFill();
/**
* Gibt an, ob aktuell eine sichtbare Füllung konfiguriert ist.
* <p>
* Eine Füllung gilt als sichtbar, wenn eine nciht transparente Füllfarbe
* oder ein Farbverlauf eingestellt ist.
*
* @return {@code true}, wenn die Füllung sichtbar ist, {@code false} sonst.
*/
default boolean hasFill() {
return (hasFillColor() && getFillColor().getAlpha() > 0) || hasGradient();
}
/**
* Gibt an, ob eine Füllfarbe konfiguriert ist.
* <p>
* Im Gegensatz zu {@link #hasFill()} prüft die Methode <em>nicht</em>, ob
* die Füllfarbe transparent ist.
*
* @return {@code true}, wenn eine Füllfarbe gesetzt ist.
*/
default boolean hasFillColor() {
Paint fill = getFill();
return fill instanceof Color;
}
/**
* Gibt an, ob ein Farbverlauf konfiguriert ist.
*
* @return {@code true}, wenn ein Farbverlauf gesetzt ist.
*/
default boolean hasGradient() {
Paint fill = getFill();
return fill instanceof GradientPaint;
}
/**
* Gibt die aktuelle Füllfarbe der Form zurück.
*
* @return Die aktuelle Füllfarbe oder {@code null}.
*/
default Color getFillColor() {
if( hasFillColor() ) {
return (Color) getFill();
} else {
return null;
}
}
/**
* Setzt die Füllfarbe auf die angegebene Farbe.
*
* @param color Die neue Füllfarbe oder {@code null}.
* @see Color
*/
default void setFillColor( Color color ) {
setFill(color);
}
/**
* Setzt die Füllfarbe auf die angegebene Farbe und setzt die Transparenz
* auf den angegebenen Wert. 0 is komplett durchsichtig und 255 komplett
* deckend.
*
* @param color Die neue Füllfarbe oder {@code null}.
* @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(Color, int)
*/
default void setFillColor( Color color, int alpha ) {
setFillColor(new Color(color, alpha));
}
/**
* Setzt die Füllfarbe auf einen Grauwert mit der angegebenen Intensität. 0
* entspricht schwarz, 255 entspricht weiß.
*
* @param gray Ein Grauwert zwischen 0 und 255.
* @see Color#Color(int)
*/
default void setFillColor( int gray ) {
setFillColor(gray, gray, gray, 255);
}
/**
* Setzt die Füllfarbe auf einen Grauwert mit der angegebenen Intensität und
* dem angegebenen Transparenzwert. Der Grauwert 0 entspricht schwarz, 255
* entspricht weiß.
*
* @param gray Ein Grauwert zwischen 0 und 255.
* @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(int, int)
*/
default void setFillColor( int gray, int alpha ) {
setFillColor(gray, gray, gray, alpha);
}
/**
* Setzt die Füllfarbe auf die Farbe mit den angegebenen Rot-, Grün- und
* Blauanteilen.
*
* @param red Der Rotanteil der Farbe zwischen 0 und 255.
* @param green Der Grünanteil der Farbe zwischen 0 und 255.
* @param blue Der Blauanteil der Farbe zwischen 0 und 255.
* @see Color#Color(int, int, int)
* @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/
default void setFillColor( int red, int green, int blue ) {
setFillColor(red, green, blue, 255);
}
/**
* Setzt die Füllfarbe auf die Farbe mit den angegebenen Rot-, Grün- und
* Blauanteilen und dem angegebenen Transparenzwert.
*
* @param red Der Rotanteil der Farbe zwischen 0 und 255.
* @param green Der Grünanteil der Farbe zwischen 0 und 255.
* @param blue Der Blauanteil der Farbe zwischen 0 und 255.
* @param alpha Ein Transparenzwert zwischen 0 und 25
* @see Color#Color(int, int, int, int)
* @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/
default void setFillColor( int red, int green, int blue, int alpha ) {
setFillColor(new Color(red, green, blue, alpha));
}
/**
* Entfernt die Füllung der Form.
*/
default void noFill() {
setFillColor(null);
noGradient();
}
/**
* Setzt die Füllfarbe auf den Standardwert zurück.
*
* @see schule.ngb.zm.Constants#DEFAULT_FILLCOLOR
*/
default void resetFill() {
setFillColor(Constants.DEFAULT_FILLCOLOR);
noGradient();
}
/**
* Gibt den aktuellen Farbverlauf der Form zurück.
*
* @return Der aktuelle Farbverlauf oder {@code null}.
*/
default GradientPaint getGradient() {
if( hasGradient() ) {
return (GradientPaint) getFill();
} else {
return null;
}
}
/**
* Setzt die Füllung auf einen linearen Farbverlauf, der am Punkt
* ({@code fromX}, {@code fromY}) mit der Farbe {@code from} startet und am
* Punkt (({@code toX}, {@code toY}) mit der Farbe {@code to} endet.
*
* @param fromX x-Koordinate des Startpunktes.
* @param fromY y-Koordinate des Startpunktes.
* @param from Farbe am Startpunkt.
* @param toX x-Koordinate des Endpunktes.
* @param toY y-Koordinate des Endpunktes.
* @param to Farbe am Endpunkt.
*/
default void setGradient( double fromX, double fromY, Color from, double toX, double toY, Color to ) {
setFill(new GradientPaint(
(float) fromX, (float) fromY, from.getJavaColor(),
(float) toX, (float) toY, to.getJavaColor()
));
}
/**
* Setzt die Füllung auf einen linearen Farbverlauf, der in die angegebene
* Richtung verläuft.
*
* @param from Farbe am Startpunkt.
* @param to Farbe am Endpunkt.
* @param dir Richtung des Farbverlaufs.
*/
default void setGradient( Color from, Color to, Options.Direction dir ) {
int whalf = (Constants.canvasWidth / 2);
int hhalf = (Constants.canvasHeight / 2);
setGradient(whalf - dir.x * whalf, hhalf - dir.y * hhalf, from, whalf + dir.x * whalf, hhalf + dir.y * hhalf, to);
}
/**
* Setzt die Füllung auf einen kreisförmigen (radialen) Farbverlauf, mit dem
* Zentrum im Punkt ({@code centerX}, {@code centerY}) und dem angegebenen
* Radius. Der Verlauf starte im Zentrum mit der Farbe {@code from} und
* endet am Rand des durch den Radius beschriebenen Kreises mit der Farbe
* {@code to}.
*
* @param centerX x-Koordinate des Kreismittelpunktes.
* @param centerY y-Koordinate des Kreismittelpunktes.
* @param radius Radius des Kreises.
* @param from Farbe im Zentrum des Kreises.
* @param to Farbe am Rand des Kreises.
*/
default void setGradient( double centerX, double centerY, double radius, Color from, Color to ) {
setFill(new RadialGradientPaint(
(float) centerX, (float) centerY, (float) radius,
new float[]{0f, 1f},
new java.awt.Color[]{from.getJavaColor(), to.getJavaColor()}));
}
/**
* Setzt die Füllung auf einen kreisförmigen (radialen) Farbverlauf, der im
* Zentrum beginnt.
*
* @param from Farbe im Zentrum.
* @param to Farbe am Rand.
*/
default void setGradient( Color from, Color to ) {
int whalf = (Constants.canvasWidth / 2);
int hhalf = (Constants.canvasHeight / 2);
setGradient(whalf, hhalf, Math.min(whalf, hhalf), from, to);
}
/**
* Entfernt den Farbverlauf von der Form.
*/
default void noGradient() {
setFill(null);
}
}

View File

@@ -1,213 +0,0 @@
package schule.ngb.zm.shapes;
import schule.ngb.zm.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
/**
* Basisklasse für Formen, die eine Füllung besitzen können.
* <p>
* Formen mit einer Füllung können auch immer eine Konturlinie besitzen.
*/
public abstract class FilledShape extends StrokedShape {
/**
* Die aktuelle Füllfarbe der Form oder {@code null}, wenn die Form nicht
* gefüllt werden soll.
*/
protected Color fillColor = DEFAULT_FILLCOLOR;
/**
* Der aktuelle Farbverlauf der Form oder {@code null}, wenn die Form keinen
* Farbverlauf besitzt.
*/
protected Paint fill = null;
/**
* Gibt die aktuelle Füllfarbe der Form zurück.
*
* @return Die aktuelle Füllfarbe oder {@code null}.
*/
public Color getFillColor() {
return fillColor;
}
/**
* Setzt die Füllfarbe auf die angegebene Farbe.
*
* @param color Die neue Füllfarbe oder {@code null}.
* @see Color
*/
public void setFillColor( Color color ) {
fillColor = color;
}
/**
* Setzt die Füllfarbe auf die angegebene Farbe und setzt die Transparenz
* auf den angegebenen Wert. 0 is komplett durchsichtig und 255 komplett
* deckend.
*
* @param color Die neue Füllfarbe oder {@code null}.
* @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(Color, int)
*/
public void setFillColor( Color color, int alpha ) {
setFillColor(new Color(color, alpha));
}
/**
* Setzt die Füllfarbe auf einen Grauwert mit der angegebenen Intensität. 0
* entspricht schwarz, 255 entspricht weiß.
*
* @param gray Ein Grauwert zwischen 0 und 255.
* @see Color#Color(int)
*/
public void setFillColor( int gray ) {
setFillColor(gray, gray, gray, 255);
}
/**
* Setzt die Füllfarbe auf einen Grauwert mit der angegebenen Intensität und
* dem angegebenen Transparenzwert. Der Grauwert 0 entspricht schwarz, 255
* entspricht weiß.
*
* @param gray Ein Grauwert zwischen 0 und 255.
* @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(int, int)
*/
public void setFillColor( int gray, int alpha ) {
setFillColor(gray, gray, gray, alpha);
}
/**
* Setzt die Füllfarbe auf die Farbe mit den angegebenen Rot-, Grün- und
* Blauanteilen.
*
* @param red Der Rotanteil der Farbe zwischen 0 und 255.
* @param green Der Grünanteil der Farbe zwischen 0 und 255.
* @param blue Der Blauanteil der Farbe zwischen 0 und 255.
* @see Color#Color(int, int, int)
* @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/
public void setFillColor( int red, int green, int blue ) {
setFillColor(red, green, blue, 255);
}
/**
* Setzt die Füllfarbe auf die Farbe mit den angegebenen Rot-, Grün- und
* Blauanteilen und dem angegebenen Transparenzwert.
*
* @param red Der Rotanteil der Farbe zwischen 0 und 255.
* @param green Der Grünanteil der Farbe zwischen 0 und 255.
* @param blue Der Blauanteil der Farbe zwischen 0 und 255.
* @param alpha Ein Transparenzwert zwischen 0 und 25
* @see Color#Color(int, int, int, int)
* @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/
public void setFillColor( int red, int green, int blue, int alpha ) {
setFillColor(new Color(red, green, blue, alpha));
}
/**
* Entfernt die Füllung der Form.
*/
public void noFill() {
setFillColor(null);
noGradient();
}
/**
* Setzt die Füllfarbe auf den Standardwert zurück.
*
* @see schule.ngb.zm.Constants#DEFAULT_FILLCOLOR
*/
public void resetFill() {
setFillColor(DEFAULT_FILLCOLOR);
noGradient();
}
/**
* Setzt die Füllung auf einen linearen Farbverlauf, der am Punkt
* ({@code fromX}, {@code fromY}) mit der Farbe {@code from} startet und am
* Punkt (({@code toX}, {@code toY}) mit der Farbe {@code to} endet.
*
* @param fromX x-Koordinate des Startpunktes.
* @param fromY y-Koordinate des Startpunktes.
* @param from Farbe am Startpunkt.
* @param toX x-Koordinate des Endpunktes.
* @param toY y-Koordinate des Endpunktes.
* @param to Farbe am Endpunkt.
*/
public void setGradient( double fromX, double fromY, Color from, double toX, double toY, Color to ) {
setFillColor(from);
fill = new GradientPaint(
(float) fromX, (float) fromY, from.getJavaColor(),
(float) toX, (float) toY, to.getJavaColor()
);
}
/**
* Setzt die Füllung auf einen kreisförmigen (radialen) Farbverlauf, mit dem
* Zentrum im Punkt ({@code centerX}, {@code centerY}) und dem angegebenen
* Radius. Der Verlauf starte im Zentrum mit der Farbe {@code from} und
* endet am Rand des durch den Radius beschriebenen Kreises mit der Farbe
* {@code to}.
*
* @param centerX x-Koordinate des Kreismittelpunktes.
* @param centerY y-Koordinate des Kreismittelpunktes.
* @param radius Radius des Kreises.
* @param from Farbe im Zentrum des Kreises.
* @param to Farbe am Rand des Kreises.
*/
public void setGradient( double centerX, double centerY, double radius, Color from, Color to ) {
setFillColor(from);
fill = new RadialGradientPaint(
(float) centerX, (float) centerY, (float) radius,
new float[]{0f, 1f},
new java.awt.Color[]{from.getJavaColor(), to.getJavaColor()});
}
/**
* Entfernt den Farbverlauf von der Form.
*/
public void noGradient() {
fill = null;
}
public Paint getPaint() {
if( fill != null ) {
return fill;
} else if( fillColor != null && fillColor.getAlpha() > 0 ) {
return fillColor;
} else {
return null;
}
}
/**
* Hilfsmethode für Unterklassen, um die angegebene Form mit der aktuellen
* Füllung auf den Grafik-Kontext zu zeichnen. Die Methode verändert
* gegebenenfalls die aktuelle Farbe des Grafikobjekts und setzt sie nicht
* auf den Ursprungswert zurück, wie von {@link #draw(Graphics2D)}
* gefordert. Dies sollte die aufrufende Unterklasse übernehmen.
*
* @param shape Die zu zeichnende Java-AWT Form
* @param graphics Das Grafikobjekt.
*/
protected void fillShape( java.awt.Shape shape, Graphics2D graphics ) {
if( fill != null ) {
graphics.setPaint(fill);
graphics.fill(shape);
} else if( fillColor != null && fillColor.getAlpha() > 0 ) {
graphics.setColor(fillColor.getJavaColor());
graphics.fill(shape);
}
}
}

View File

@@ -1,9 +1,14 @@
package schule.ngb.zm.shapes; package schule.ngb.zm.shapes;
import schule.ngb.zm.BasicDrawable;
import schule.ngb.zm.Color;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Options; import schule.ngb.zm.Options;
import java.awt.Color; import java.awt.GradientPaint;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
@@ -34,7 +39,7 @@ import java.awt.geom.Point2D;
* eine {@link #equals(Object)} Methode. * eine {@link #equals(Object)} Methode.
*/ */
@SuppressWarnings( "unused" ) @SuppressWarnings( "unused" )
public abstract class Shape extends FilledShape { public abstract class Shape extends BasicDrawable {
/** /**
* x-Koordinate der Form. * x-Koordinate der Form.
@@ -56,11 +61,6 @@ public abstract class Shape extends FilledShape {
*/ */
protected double scale = 1.0; protected double scale = 1.0;
/**
* Ob die Form angezeigt werden soll.
*/
protected boolean visible = true;
/** /**
* Ankerpunkt der Form. * Ankerpunkt der Form.
*/ */
@@ -84,38 +84,6 @@ public abstract class Shape extends FilledShape {
this.y = y; this.y = y;
} }
/**
* Ob die Form angezeigt wird oder nicht.
*
* @return {@code true}, wenn die From angezeigt werden soll, {@code false}
* sonst.
*/
public boolean isVisible() {
return visible;
}
/**
* Versteckt die Form.
*/
public void hide() {
visible = false;
}
/**
* Zeigt die Form an.
*/
public void show() {
visible = true;
}
/**
* Versteckt die Form, wenn sie derzeit angezeigt wird und zeigt sie
* andernfalls an.
*/
public void toggle() {
visible = !visible;
}
/** /**
* Gibt die x-Koordinate der Form zurück. * Gibt die x-Koordinate der Form zurück.
* *
@@ -180,6 +148,25 @@ public abstract class Shape extends FilledShape {
*/ */
public abstract double getHeight(); public abstract double getHeight();
/**
* {@inheritDoc}
*/
@Override
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to, Options.Direction dir ) {
Point2D apDir = getAbsAnchorPoint(dir);
Point2D apInv = getAbsAnchorPoint(dir.inverse());
setGradient(apInv.getX(), apInv.getY(), from, apDir.getX(), apDir.getY(), to);
}
/**
* {@inheritDoc}
*/
@Override
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to ) {
Point2D ap = getAbsAnchorPoint(CENTER);
setGradient(ap.getX(), ap.getY(), Math.min(ap.getX(), ap.getY()), from, to);
}
/** /**
* Gibt die Rotation in Grad zurück. * Gibt die Rotation in Grad zurück.
* *
@@ -237,17 +224,6 @@ public abstract class Shape extends FilledShape {
scale(scale * factor); scale(scale * factor);
} }
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to, Options.Direction dir ) {
Point2D apDir = getAbsAnchorPoint(dir);
Point2D apInv = getAbsAnchorPoint(dir.inverse());
setGradient(apInv.getX(), apInv.getY(), from, apDir.getX(), apDir.getY(), to);
}
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to ) {
Point2D ap = getAbsAnchorPoint(CENTER);
setGradient(ap.getX(), ap.getY(), Math.min(ap.getX(), ap.getY()), from, to);
}
public Options.Direction getAnchor() { public Options.Direction getAnchor() {
return anchor; return anchor;
} }
@@ -548,7 +524,7 @@ public abstract class Shape extends FilledShape {
shape = transform.createTransformedShape(shape); shape = transform.createTransformedShape(shape);
} }
Color currentColor = graphics.getColor(); java.awt.Color currentColor = graphics.getColor();
fillShape(shape, graphics); fillShape(shape, graphics);
strokeShape(shape, graphics); strokeShape(shape, graphics);
graphics.setColor(currentColor); graphics.setColor(currentColor);
@@ -561,8 +537,8 @@ public abstract class Shape extends FilledShape {
* verglichen. Unterklassen überschreiben die Methode, um weitere * verglichen. Unterklassen überschreiben die Methode, um weitere
* Eigenschaften zu berücksichtigen. * Eigenschaften zu berücksichtigen.
* <p> * <p>
* Die Eigenschaften von {@link FilledShape} und {@link StrokedShape} werden * Die Eigenschaften, die durch {@link Fillable} und {@link Strokeable}
* nicht verglichen. * impliziert werden, werden nicht verglichen.
* *
* @param o Ein anderes Objekt. * @param o Ein anderes Objekt.
* @return * @return
@@ -578,4 +554,43 @@ public abstract class Shape extends FilledShape {
Double.compare(pShape.scale, scale) == 0; Double.compare(pShape.scale, scale) == 0;
} }
/**
* Hilfsmethode für Unterklassen, um die angegebene Form mit den aktuellen
* Kontureigenschaften auf den Grafik-Kontext zu zeichnen. Die Methode
* verändert gegebenenfalls die aktuelle Farbe des Grafikobjekts und setzt
* sie nicht auf den Ursprungswert zurück, wie von {@link #draw(Graphics2D)}
* gefordert. Dies sollte die aufrufende Unterklasse übernehmen.
*
* @param shape Die zu zeichnende Java-AWT Form
* @param graphics Das Grafikobjekt.
*/
protected void strokeShape( java.awt.Shape shape, Graphics2D graphics ) {
if( strokeColor != null && strokeColor.getAlpha() > 0
&& strokeWeight > 0.0 ) {
graphics.setColor(strokeColor.getJavaColor());
graphics.setStroke(getStroke());
graphics.draw(shape);
}
}
/**
* Hilfsmethode für Unterklassen, um die angegebene Form mit der aktuellen
* Füllung auf den Grafik-Kontext zu zeichnen. Die Methode verändert
* gegebenenfalls die aktuelle Farbe des Grafikobjekts und setzt sie nicht
* auf den Ursprungswert zurück, wie von {@link #draw(Graphics2D)}
* gefordert. Dies sollte die aufrufende Unterklasse übernehmen.
*
* @param shape Die zu zeichnende Java-AWT Form
* @param graphics Das Grafikobjekt.
*/
protected void fillShape( java.awt.Shape shape, Graphics2D graphics ) {
if( fill != null ) {
graphics.setPaint(fill);
graphics.fill(shape);
} else if( fillColor != null && fillColor.getAlpha() > 0 ) {
graphics.setColor(fillColor.getJavaColor());
graphics.fill(shape);
}
}
} }

View File

@@ -6,46 +6,66 @@ import schule.ngb.zm.Drawable;
import schule.ngb.zm.Options; import schule.ngb.zm.Options;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Stroke; import java.awt.Stroke;
/** /**
* Basisklasse für Formen, die eine Konturlinie besitzen. * {@link Drawable} Klassen, die mit einer Konturlinie versehen werden können.
* <p>
* Das {@code Strokeable} Interface dient hauptsächlich zur Vereinheitlichung
* der API für Konturlinien. Durch Implementation wird sichergestellt, dass alle
* Objekte, die eine Konturlinie haben können, dieselben Methoden zur Verfügung
* stellen. Wenn eine {@link Shape} eine
* {@link Strokeable#setStrokeColor(Color, int)} Methode hat, dann sollte auch
* eine {@link schule.ngb.zm.layers.TurtleLayer.Turtle} dieselbe Methode
* anbieten. Im Einzelfall kann es sinnvoll sein, weitere Methoden für
* Konturlinien zur erfügung zu stellen. Allerdings sollte davon nach
* Möglichkeit zugunsten einer einheitlichen API abgesehen werden.
* <p>
* Das Äquivalent für Füllungen stellt {@link Fillable} dar.
*/ */
public abstract class StrokedShape extends Constants implements Drawable { public interface Strokeable extends Drawable {
/** /**
* Aktuelle Farbe der Konturlinie oder {@code null}, wenn die Form ohne * Setzt den {@code Stroke} für die Konturlinie direkt.
* kontur dargestellt werden soll. *
* @param stroke Ein {@code Stroke}-Objekt.
*/ */
protected Color strokeColor = DEFAULT_STROKECOLOR; void setStroke( Stroke stroke );
/** /**
* Die Dicke der Konturlinie. Wird nicht kleiner als 0. * Gibt ein {@code Stroke}-Objekt mit den aktuell gesetzten Eigenschaften
* zurück.
*
* @return Ein {@code Stroke} mit den passenden Kontureigenschaften.
*/ */
protected double strokeWeight = DEFAULT_STROKEWEIGHT; Stroke getStroke();
/** /**
* Die Art der Konturlinie. * Gibt an, ob die aktuell gesetzten Eigenschaften eine sichtbare
* Konturlinie erzeugen.
* <p>
* Die Konturlinie gilt als sichtbar, wenn sie eine nicht transparente Farbe
* und eine Dicke größer 0 besitzt.
* <p>
* Das bedeutet, falls die Methode {@code false} zurückgibt, dann kann
* {@link #getStroke()} trotzdem ein gültiges {@link Stroke}-Objekt
* zurückgeben, beispielsweise wenn keine Farbe gesetzt wurde.
*
* @return {@code true}, wenn die Konturlinie sichtbar ist, {@code false}
* sonst.
*/ */
protected Options.StrokeType strokeType = SOLID; default boolean hasStroke() {
Color strokeColor = getStrokeColor();
/** double strokeWeight = getStrokeWeight();
* Cache für den aktuellen {@code Stroke} der Kontur. Wird nach Änderung return strokeColor != null && strokeColor.getAlpha() > 0 && strokeWeight > 0;
* einer der Kontureigenschaften auf {@code null} gesetzt und beim nächsten }
* Zeichnen neu erstellt.
*/
protected Stroke stroke = null;
/** /**
* Gibt die aktuelle Farbe der Konturlinie zurück. * Gibt die aktuelle Farbe der Konturlinie zurück.
* *
* @return Die Konturfarbe oder {@code null}. * @return Die Konturfarbe oder {@code null}.
*/ */
public Color getStrokeColor() { Color getStrokeColor();
return strokeColor;
}
/** /**
* Setzt die Farbe der Konturlinie auf die angegebene Farbe. * Setzt die Farbe der Konturlinie auf die angegebene Farbe.
@@ -53,9 +73,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @param color Die neue Farbe der Konturlinie. * @param color Die neue Farbe der Konturlinie.
* @see Color * @see Color
*/ */
public void setStrokeColor( Color color ) { void setStrokeColor( Color color );
this.strokeColor = color;
}
/** /**
* Setzt die Farbe der Konturlinie auf die angegebene Farbe und setzt die * Setzt die Farbe der Konturlinie auf die angegebene Farbe und setzt die
@@ -66,7 +84,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @param alpha Ein Transparenzwert zwischen 0 und 255. * @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(Color, int) * @see Color#Color(Color, int)
*/ */
public void setStrokeColor( Color color, int alpha ) { default void setStrokeColor( Color color, int alpha ) {
setStrokeColor(new Color(color, alpha)); setStrokeColor(new Color(color, alpha));
} }
@@ -77,7 +95,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @param gray Ein Grauwert zwischen 0 und 255. * @param gray Ein Grauwert zwischen 0 und 255.
* @see Color#Color(int) * @see Color#Color(int)
*/ */
public void setStrokeColor( int gray ) { default void setStrokeColor( int gray ) {
setStrokeColor(gray, gray, gray, 255); setStrokeColor(gray, gray, gray, 255);
} }
@@ -90,7 +108,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @param alpha Ein Transparenzwert zwischen 0 und 255. * @param alpha Ein Transparenzwert zwischen 0 und 255.
* @see Color#Color(int, int) * @see Color#Color(int, int)
*/ */
public void setStrokeColor( int gray, int alpha ) { default void setStrokeColor( int gray, int alpha ) {
setStrokeColor(gray, gray, gray, alpha); setStrokeColor(gray, gray, gray, alpha);
} }
@@ -105,7 +123,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @see <a * @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a> * href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/ */
public void setStrokeColor( int red, int green, int blue ) { default void setStrokeColor( int red, int green, int blue ) {
setStrokeColor(red, green, blue, 255); setStrokeColor(red, green, blue, 255);
} }
@@ -121,14 +139,14 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @see <a * @see <a
* href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a> * href="https://de.wikipedia.org/wiki/RGB-Farbraum">https://de.wikipedia.org/wiki/RGB-Farbraum</a>
*/ */
public void setStrokeColor( int red, int green, int blue, int alpha ) { default void setStrokeColor( int red, int green, int blue, int alpha ) {
setStrokeColor(new Color(red, green, blue, alpha)); setStrokeColor(new Color(red, green, blue, alpha));
} }
/** /**
* Entfernt die Kontur der Form. * Entfernt die Kontur der Form.
*/ */
public void noStroke() { default void noStroke() {
setStrokeColor(null); setStrokeColor(null);
} }
@@ -139,10 +157,10 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @see schule.ngb.zm.Constants#DEFAULT_STROKEWEIGHT * @see schule.ngb.zm.Constants#DEFAULT_STROKEWEIGHT
* @see schule.ngb.zm.Constants#SOLID * @see schule.ngb.zm.Constants#SOLID
*/ */
public void resetStroke() { default void resetStroke() {
setStrokeColor(DEFAULT_STROKECOLOR); setStrokeColor(Constants.DEFAULT_STROKECOLOR);
setStrokeWeight(DEFAULT_STROKEWEIGHT); setStrokeWeight(Constants.DEFAULT_STROKEWEIGHT);
setStrokeType(SOLID); setStrokeType(Constants.SOLID);
} }
/** /**
@@ -150,9 +168,7 @@ public abstract class StrokedShape extends Constants implements Drawable {
* *
* @return Die aktuelle Dicke der Linie. * @return Die aktuelle Dicke der Linie.
*/ */
public double getStrokeWeight() { double getStrokeWeight();
return strokeWeight;
}
/** /**
* Setzt die Dicke der Konturlinie. Die Dicke muss größer 0 sein. Wird 0 * Setzt die Dicke der Konturlinie. Die Dicke muss größer 0 sein. Wird 0
@@ -160,9 +176,8 @@ public abstract class StrokedShape extends Constants implements Drawable {
* *
* @param weight Die Dicke der Konturlinie. * @param weight Die Dicke der Konturlinie.
*/ */
public void setStrokeWeight( double weight ) { default void setStrokeWeight( double weight ) {
this.strokeWeight = max(0.0, weight); setStroke(createStroke(getStrokeType(), weight));
this.stroke = null;
} }
/** /**
@@ -171,25 +186,19 @@ public abstract class StrokedShape extends Constants implements Drawable {
* @return Die aktuelle Art der Konturlinie. * @return Die aktuelle Art der Konturlinie.
* @see Options.StrokeType * @see Options.StrokeType
*/ */
public Options.StrokeType getStrokeType() { Options.StrokeType getStrokeType();
return strokeType;
}
/** /**
* Setzt den Typ der Kontur. Erlaubte Werte sind {@link #DASHED}, * Setzt den Typ der Kontur. Erlaubte Werte sind {@link Constants#DASHED},
* {@link #DOTTED} und {@link #SOLID}. * {@link Constants#DOTTED} und {@link Constants#SOLID}.
* *
* @param type Eine der möglichen Konturarten. * @param type Eine der möglichen Konturarten.
* @see Options.StrokeType * @see Options.StrokeType
*/ */
public void setStrokeType( Options.StrokeType type ) { default void setStrokeType( Options.StrokeType type ) {
this.strokeType = type; setStroke(createStroke(type, getStrokeWeight()));
this.stroke = null;
} }
@Override
public abstract void draw( Graphics2D graphics );
/** /**
* Hilfsmethode, um ein {@link Stroke} Objekt mit den aktuellen * Hilfsmethode, um ein {@link Stroke} Objekt mit den aktuellen
* Kontureigenschaften zu erstellen. Der aktuelle {@code Stroke} wird * Kontureigenschaften zu erstellen. Der aktuelle {@code Stroke} wird
@@ -197,52 +206,26 @@ public abstract class StrokedShape extends Constants implements Drawable {
* *
* @return Ein {@code Stroke} mit den passenden Kontureigenschaften. * @return Ein {@code Stroke} mit den passenden Kontureigenschaften.
*/ */
public Stroke getStroke() { static Stroke createStroke( Options.StrokeType strokeType, double strokeWeight ) {
// TODO: Used global cached Stroke Objects? switch( strokeType ) {
if( stroke == null ) { case DOTTED:
switch( strokeType ) { return new BasicStroke(
case DOTTED: (float) strokeWeight,
stroke = new BasicStroke( BasicStroke.CAP_ROUND,
(float) strokeWeight, BasicStroke.JOIN_ROUND,
BasicStroke.CAP_ROUND, 10.0f, new float[]{1.0f, 5.0f}, 0.0f);
BasicStroke.JOIN_ROUND, case DASHED:
10.0f, new float[]{1.0f, 5.0f}, 0.0f); return new BasicStroke(
break; (float) strokeWeight,
case DASHED: BasicStroke.CAP_ROUND,
stroke = new BasicStroke( BasicStroke.JOIN_ROUND,
(float) strokeWeight, 10.0f, new float[]{5.0f}, 0.0f);
BasicStroke.CAP_ROUND, case SOLID:
BasicStroke.JOIN_ROUND, default:
10.0f, new float[]{5.0f}, 0.0f); return new BasicStroke(
break; (float) strokeWeight,
case SOLID: BasicStroke.CAP_ROUND,
default: BasicStroke.JOIN_ROUND);
stroke = new BasicStroke(
(float) strokeWeight,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
break;
}
}
return stroke;
}
/**
* Hilfsmethode für Unterklassen, um die angegebene Form mit den aktuellen
* Kontureigenschaften auf den Grafik-Kontext zu zeichnen. Die Methode
* verändert gegebenenfalls die aktuelle Farbe des Grafikobjekts und setzt
* sie nicht auf den Ursprungswert zurück, wie von {@link #draw(Graphics2D)}
* gefordert. Dies sollte die aufrufende Unterklasse übernehmen.
*
* @param shape Die zu zeichnende Java-AWT Form
* @param graphics Das Grafikobjekt.
*/
protected void strokeShape( java.awt.Shape shape, Graphics2D graphics ) {
if( strokeColor != null && strokeColor.getAlpha() > 0
&& strokeWeight > 0.0 ) {
graphics.setColor(strokeColor.getJavaColor());
graphics.setStroke(getStroke());
graphics.draw(shape);
} }
} }