Dokumentatione

This commit is contained in:
ngb 2022-12-11 13:35:30 +01:00
parent ce3ffee4da
commit 788ed888e9
1 changed files with 323 additions and 95 deletions

View File

@ -4,13 +4,14 @@ import schule.ngb.zm.BasicDrawable;
import schule.ngb.zm.Fillable;
import schule.ngb.zm.Options;
import schule.ngb.zm.Strokeable;
import schule.ngb.zm.util.Validator;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
/**
* Basisklasse für alle Formen in der Zeichenmaschine.
* Dies ist die Basisklasse für alle Formen in der Zeichenmaschine.
* <p>
* Alle Formen sind als Unterklassen von {@code Shape} implementiert.
* <p>
@ -19,7 +20,6 @@ import java.awt.geom.Point2D;
* Parametern initialisiert und einen, der die Werte einer anderen Form
* desselben Typs übernimmt. In der Klasse {@link Circle} sind die Konstruktoren
* beispielsweise so implementiert:
*
* <pre><code>
* public Circle( double x, double y, double radius ) {
* super(x, y);
@ -39,42 +39,42 @@ import java.awt.geom.Point2D;
public abstract class Shape extends BasicDrawable {
/**
* x-Koordinate der Form.
* Speichert die x-Koordinate der Form.
*/
protected double x;
/**
* y-Koordinate der Form.
* Speichert die y-Koordinate der Form.
*/
protected double y;
/**
* Rotation in Grad um den Punkt (x, y).
* Speichert die Rotation in Grad um den Punkt (x, y).
*/
protected double rotation = 0.0;
/**
* Skalierungsfaktor.
* Speichert den Skalierungsfaktor.
*/
protected double scale = 1.0;
/**
* Ankerpunkt der Form.
* Speichert den Ankerpunkt.
*/
protected Options.Direction anchor = Options.Direction.CENTER;
/**
* Setzt die x- und y-Koordinate der Form auf 0.
* Erstellt eine neue Form mit den Koordinaten {@code (0,0)}.
*/
public Shape() {
this(0.0, 0.0);
}
/**
* Setzt die x- und y-Koordinate der Form.
* Erstellt eine Form mit den angegebenen Koordinaten.
*
* @param x
* @param y
* @param x Die x-Koordinate.
* @param y Die y-Koordinate.
*/
public Shape( double x, double y ) {
this.x = x;
@ -82,7 +82,7 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Gibt die x-Koordinate der Form zurück.
* Liefert die aktuelle x-Koordinate der Form.
*
* @return Die x-Koordinate.
*/
@ -100,7 +100,7 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Gibt die y-Koordinate der Form zurück.
* Liefert die aktuelle y-Koordinate der Form.
*
* @return Die y-Koordinate.
*/
@ -109,57 +109,44 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Setzt die y-Koordinate der Form.
* Setzt die x-Koordinate der Form.
*
* @param y Die neue y-Koordinate.
* @param y Die neue y-Koordinate der Form.
*/
public void setY( double y ) {
this.y = y;
}
/**
* Gibt die Breite dieser Form zurück.
* Liefert die aktuelle Breite dieser Form.
* <p>
* Die Breite einer Form ist immer die Breite ihrer Begrenzung,
* <strong>bevor</strong> Drehungen und andere Transformationen auf sie
* angewandt wurden.
* <p>
* Die Begrenzungen der tatsächlich gezeichneten Form kann mit
* {@link #getBounds()} abgerufen werden.
* Die Begrenzungen der tatsächlich gezeichneten Form wird mit
* {@link #getBounds()} abgerufen.
*
* @return
* @return Die Breite der Form.
*/
public abstract double getWidth();
/**
* Gibt die Höhe dieser Form zurück.
* Liefert die aktuelle Höhe dieser Form.
* <p>
* Die Höhe einer Form ist immer die Höhe ihrer Begrenzung,
* <strong>bevor</strong> Drehungen und andere Transformationen auf sie
* angewandt wurden.
* <p>
* Die Begrenzungen der tatsächlich gezeichneten Form kann mit
* {@link #getBounds()} abgerufen werden.
* Die Begrenzungen der tatsächlich gezeichneten Form wird mit
* {@link #getBounds()} abgerufen.
*
* @return
* @return Die Höhe der Form.
*/
public abstract double getHeight();
@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);
}
@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.
* Liefert die Rotation in Grad.
*
* @return Rotation in Grad.
*/
@ -176,14 +163,25 @@ public abstract class Shape extends BasicDrawable {
this.rotation += angle % 360;
}
public void rotateTo( double angle ) {
this.rotation = angle % 360;
}
/**
* Dreht die Form um den angegebenen Winkel um das angegebene Drehzentrum.
*
* @param center Das Drehzentrum der Drehung.
* @param angle Der Drehwinkel.
*/
public void rotate( Point2D center, double angle ) {
Validator.requireNotNull(center, "center");
rotate(center.getX(), center.getY(), angle);
}
/**
* Dreht die Form um den angegebenen Drehwinkel um die angegbenen
* Koordinaten als Drehzentrum.
*
* @param x x-Koordiante des Drehzentrums.
* @param y y-Koordiante des Drehzentrums.
* @param angle Drehwinkel in Grad.
*/
public void rotate( double x, double y, double angle ) {
this.rotation += angle % 360;
@ -198,6 +196,15 @@ public abstract class Shape extends BasicDrawable {
this.y = y2 + y;
}
/**
* Setzt die Drehung der Form auf den angegebenen Winkel.
*
* @param angle Drehwinkel in Grad.
*/
public void rotateTo( double angle ) {
this.rotation = angle % 360;
}
/**
* Gibt den aktuellen Skalierungsfaktor zurück.
*
@ -207,33 +214,91 @@ public abstract class Shape extends BasicDrawable {
return scale;
}
/**
* Setzt den Skalierungsfaktor auf den angegebenen Faktor.
* <p>
* Bei einem Faktor größer 0 wird die Form vergrößert, bei einem Faktor
* kleiner 0 verkleinert. Bei negativen Werten wird die Form entlang der x-
* bzw. y-Achse gespiegelt.
* <p>
* Das Seitenverhältnis wird immer beibehalten.
*
* @param factor Der Skalierungsfaktor.
*/
public void scale( double factor ) {
scale = factor;
}
/**
* Skaliert die Form um den angegebenen Faktor.
* <p>
* Bei einem Faktor größer 0 wird die Form vergrößert, bei einem Faktor
* kleiner 0 verkleinert. Bei negativen Werten wird die Form entlang der x-
* bzw. y-Achse gespiegelt.
* <p>
* Die Skalierung wird zusätzlich zur aktuellen Skalierung angewandt. Wurde
* die Form zuvor um den Faktor 0.5 verkleinert und wird dann um 1.5
* vergrößert, dann ist die Form im Anschluss ein Drittel kleiner als zu
* Beginn ({@code 0.5 * 1.5 = 0.75}).
*
* @param factor Der Skalierungsfaktor.
*/
public void scaleBy( double factor ) {
scale(scale * factor);
}
/**
* Liefert den aktuellen Ankerpunkt der Form.
*
* @return Der Ankerpunkt.
*/
public Options.Direction getAnchor() {
return anchor;
}
/**
* Setzt den Ankerpunkt der Form basierend auf der angegebenen
* {@link Options.Direction Richtung}.
* Setzt den Ankerpunkt der Form auf die angegebene Richtung.
* <p>
* 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.
* Jede Form hat einen Ankerpunkt, von dem aus sie gezeichnet wird. Jede
* {@link schule.ngb.zm.Options.Direction Richtung} beschreibt einen der
* Neun Ankerpunkte:
* <pre>
* NWNNE
*
*
* W C E
*
*
* SWSSE
* </pre>
* <p>
* Für den Ankerpunkt {@link #CENTER} wird die Form also ausgehend von den
* Koordinaten {@link #x} und {@link #y} um die Hälfte der Breite nach links
* und rechts, sowie um die Hälfte der Höhe nach oben und unten gezeichnet.
* Fpr den Ankerpunkt {@link #NORTHWEST} dagegen um die gesamte Breite nach
* rechts und die Höhe nach unten.
* <pre>
* setAnchor(CENTER) setAnchor(NORTHWEST)
*
*
*
* (x,y) (x,y)
*
*
*
*
*
*
* </pre>
* <p>
* Der Ankerpunkt der Form bestimmt bei Transformationen auch die Position
* des Drehzentrums und anderer relativer Koordinaten bezüglich der Form.
*
* @param anchor
* @param anchor Der Ankerpunkt.
*/
public void setAnchor( Options.Direction anchor ) {
if( anchor != null ) {
this.anchor = anchor;
}
Validator.requireNotNull(anchor, "anchor");
this.anchor = anchor;
}
/**
@ -242,7 +307,19 @@ public abstract class Shape extends BasicDrawable {
* <p>
* Die Koordinaten des Ankerpunktes werden relativ zur oberen linken Ecke
* des Rechtecks mit der Breite {@code width} und der Höhe {@code height}
* bestimmt.
* bestimmt. Der Ankerpunkt {@link #NORTHWEST} hat daher immer das Ergebnis
* {@code (0,0)} und {@link #SOUTHEAST} {@code (width, height)}.
* <pre>
* (0,0)(w/2,0)(w,0)
*
*
*
* (0,h/2) (w/2,h/2) (w,h/2)
*
*
*
* (0,h)(w/2,h)(w,h)
* </pre>
*
* @param width Breite des umschließenden Rechtecks.
* @param height Höhe des umschließenden Rechtecks.
@ -259,11 +336,12 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Bestimmt den Ankerpunkt der Form relativ zum gesetzten
* {@link #setAnchor(Options.Direction) Ankerpunkt}.
* Bestimmt die Koordinaten des angegebenen Ankers der Form relativ zum
* aktuellen {@link #setAnchor(Options.Direction) Ankerpunkt}.
*
* @param anchor Die Richtung des Ankerpunktes.
* @param anchor Die Richtung des Ankers.
* @return Der relative Ankerpunkt.
* @see #getAnchorPoint(double, double, Options.Direction)
*/
public Point2D.Double getAnchorPoint( Options.Direction anchor ) {
double wHalf = getWidth() * .5, hHalf = getHeight() * .5;
@ -276,11 +354,20 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Ermittelt die absoluten Koordinaten eines angegebenen
* Ermittelt die absoluten Koordinaten des angegebenen
* {@link #setAnchor(Options.Direction) Ankers}.
* <p>
* Die absoluten Koordinaten werden bestimmt durch die Position der Form
* {@code (x,y)} plus die
* {@link #getAnchorPoint(Options.Direction) relativen Koordinaten} des
* Ankers.
*
* @param anchor Die Richtung des Ankerpunktes.
* <b>Wichtig:</b> Die Berechnung berücksichtigt derzeit keine Rotationen
* und Transformationen der Form.
*
* @param anchor Die Richtung des Ankers.
* @return Der absolute Ankerpunkt.
* @see #getAnchorPoint(double, double, Options.Direction)
*/
public Point2D.Double getAbsAnchorPoint( Options.Direction anchor ) {
// TODO: Die absoluten Anker müssten eigentlich die Rotation berücksichtigen.
@ -293,20 +380,22 @@ public abstract class Shape extends BasicDrawable {
/**
* Kopiert die Eigenschaften der angegebenen Form in diese.
* <p>
* Unterklassen sollten diese Methode überschreiben, um weitere
* Eigenschaften zu kopieren (zum Beispiel den Radius eines Kreises).
* Unterklassen sollten immer mit dem Aufruf {@code super.copyFrom(shape)}
* die Basiseigenschaften kopieren.
* Unterklassen überschreiben diese Methode, um weitere Eigenschaften zu
* kopieren (zum Beispiel den Radius eines Kreises). Überschreibende
* Methoden sollten immer mit dem Aufruf {@code super.copyFrom(shape)} die
* Basiseigenschaften kopieren.
* <p>
* Die Methode sollte so viele Eigenschaften wie möglich von der anderen
* Form in diese kopieren. Wenn die andere Form einen anderen Typ hat, dann
* werden trotzdem die Basiseigenschaften (Konturlinie, Füllung, Position,
* Rotation, Skalierung, Sichtbarkeit und Ankerpunkt) in diese Form kopiert.
* Implementierende Unterklassen können soweit sinnvoll auch andere Werte
* übernehmen. Eine {@link Ellipse} kann beispielsweise auch die Breite und
* Höhe eines {@link Rectangle} übernehmen.
* Die Methode kopiert so viele Eigenschaften wie möglich von der
* angegebenen Form in diese. Wenn die andere Form einen anderen Typ hat,
* dann werden trotzdem die Basiseigenschaften (Konturlinie, Füllung,
* Position, Rotation, Skalierung, Sichtbarkeit und Ankerpunkt) in diese
* Form kopiert. Soweit sinnvoll übernehmen implementierende Unterklassen
* auch andere Werte. Eine {@link Ellipse} kopiert beispielsweise auch die
* Breite und Höhe eines {@link Rectangle}.
* <p>
* Wird {@code null} übergeben, dann passiert nichts.
*
* @param shape Die Originalform, von der kopiert werden soll.
* @param shape Die Originalform, von der kopiert wird.
*/
public void copyFrom( Shape shape ) {
if( shape != null ) {
@ -335,9 +424,9 @@ public abstract class Shape extends BasicDrawable {
* </code></pre>
* <p>
* Die Methode kann beliebig umgesetzt werden, um eine 1-zu-1-Kopie dieser
* Form zu erhalten. In der Regel sollte aber jede Form einen Konstruktor
* besitzen, die alle Werte einer andern Form übernimmt. Die gezeigte
* Implementierung dürfte daher im Regelfall ausreichend sein.
* Form zu erhalten. In der Regel besitzt aber jede Form einen Konstruktor,
* der alle Werte einer andern Form übernimmt. Die gezeigte Implementierung
* ist daher im Regelfall ausreichend.
*
* @return Eine genaue Kopie dieser Form.
*/
@ -348,8 +437,8 @@ public abstract class Shape extends BasicDrawable {
* zurück. Intern werden die AWT Shapes benutzt, um sie auf den
* {@link Graphics2D Grafikkontext} zu zeichnen.
* <p>
* Wenn diese Form nicht durch eine AWT-Shape dargestellt wird, kann die
* Methode {@code null} zurückgeben.
* Wenn diese Form nicht durch eine AWT-Shape dargestellt wird, liefert die
* Methode {@code null}.
*
* @return Eine Java-AWT {@code Shape} die diese Form repräsentiert oder
* {@code null}.
@ -369,34 +458,85 @@ public abstract class Shape extends BasicDrawable {
return new Bounds(this);
}
/**
* Verschiebt die Form um die angegebenen Werte entlang der
* Koordinatenachsen.
*
* @param dx Verschiebung entlang der x-Achse.
* @param dy Verschiebung entlang der y-Achse.
*/
public void move( double dx, double dy ) {
x += dx;
y += dy;
}
/**
* Bewegt die Form an die angegebenen Koordinaten.
*
* @param x Die neue x-Koordinate.
* @param y Die neue y-Koordinate.
*/
public void moveTo( double x, double y ) {
this.x = x;
this.y = y;
}
/**
* Bewegt die Form an dieselben Koordinaten wie die angegebene Form.
*
* @param shape Eine andere Form.
*/
public void moveTo( Shape shape ) {
moveTo(shape.getX(), shape.getY());
}
/**
* Bewegt die Form zum angegebenen Ankerpunkt der angegebenen Form.
*
* @param shape Die andere Form.
* @param dir Die Richtung des Ankerpunktes.
* @see #moveTo(Shape, Options.Direction, double)
*/
public void moveTo( Shape shape, Options.Direction dir ) {
moveTo(shape, dir, 0.0);
}
/**
* Bewegt den Ankerpunkt dieser Form zu einem Ankerpunkt einer anderen Form.
* Mit {@code buff} kann ein zusätzlicher Abstand angegeben werden, um den
* die Form entlang des Ankerpunktes {@code anchor} verschoben werden soll.
* Bewegt den Ankerpunkt dieser Form zu einem Ankerpunkt einer anderen
* Form.
* <p>
* Mit {@code buff} wird ein zusätzlicher Abstand angegeben, um den die Form
* entlang des Ankerpunktes {@code anchor} verschoben wird.
* <p>
* Ist der Anker zum Beispiel {@code NORTH}, dann wird die Form um
* {@code buff} nach oben verschoben.
* {@code buff} oberhalb der oberen Kante der zweiten Form verschoben.
* <p>
* Befinden sich die Formen zuvor in folgender Ausrichtung:
* <pre>
*
*
* W B
*
*
* W A
*
*
* </pre>
* <p>
* bringt sie der Aufruf {@code B.moveTo(A, DOWN, 0)} in diese Ausrichtung:
* <pre>
* B.moveTo(A, WEST, 0) B.moveTo(A, WEST, 10)
*
*
*
* A B A B
*
*
* </pre>
*
* @param shape
* @param dir
* @param buff
* @param shape Die andere Form.
* @param dir Die Richtung des Ankerpunktes.
* @param buff Der Abstand zum angegebenen Ankerpunkt.
*/
public void moveTo( Shape shape, Options.Direction dir, double buff ) {
Point2D ap = shape.getAbsAnchorPoint(dir);
@ -406,15 +546,22 @@ public abstract class Shape extends BasicDrawable {
}
/**
* Richtet die Form entlang der angegebenen Richtung am Rand der
* Zeichenfläche aus.
* Bewegt die Form an den Rand der Zeichenfläche in der angegebenen
* Richtung.
*
* @param dir Die Richtung der Ausrichtung.
* @param dir Die Richtung.
*/
public void alignTo( Options.Direction dir ) {
alignTo(dir, 0.0);
}
/**
* Bewegt die Form mit dem angegebenen Abstand an den Rand der Zeichenfläche
* in der angegebenen Richtung aus.
*
* @param dir Die Richtung.
* @param buff Der Abstand zum Rand.
*/
public void alignTo( Options.Direction dir, double buff ) {
Point2D anchorShape = Shape.getAnchorPoint(canvasWidth, canvasHeight, dir);
Point2D anchorThis = this.getAbsAnchorPoint(dir);
@ -423,20 +570,58 @@ public abstract class Shape extends BasicDrawable {
this.y += Math.abs(dir.y) * (anchorShape.getY() - anchorThis.getY()) + dir.y * buff;
}
/**
* Bewegt den Ankerpunkt dieser Form in der angegebenen Richtung zum
* Gleichen Ankerpunkt der anderen Form.
*
* @param shape Die andere Form.
* @param dir Die Richtung des Ankerpunktes.
* @see #alignTo(Shape, Options.Direction, double)
*/
public void alignTo( Shape shape, Options.Direction dir ) {
alignTo(shape, dir, 0.0);
}
/**
* Richtet die Form entlang der angegebenen Richtung an einer anderen Form
* aus. Für {@code DOWN} wird beispielsweise die y-Koordinate der unteren
* Kante dieser Form an der unteren Kante der angegebenen Form {@code shape}
* ausgerichtet. Die x-Koordinate wird nicht verändert. {@code buff} gibt
* einen Abstand ab, um den diese From versetzt ausgerichtet werden soll.
* aus.
* <p>
* {@code buff} gibt einen Abstand ab, um den diese From versetzt
* ausgerichtet wird.
* <p>
* Für {@link #DOWN} wird beispielsweise die y-Koordinate der unteren Kante
* dieser Form an der unteren Kante von {@code shape} ausgerichtet. Die
* x-Koordinate wird in dem Fall nicht verändert.
* <p>
* Befinden sich die Formen beispielsweise in folgender Position:
* <pre>
*
*
* B
*
* D
* A
*
* D
* </pre>
* <p>
* <p>
* werden sie durch {@code alignTo} so positioniert:
* <pre>
* B.alignTo(A, EAST, 0) B.alignTo(A, EAST, 10)
*
*
*
* A B A
* B
* D D D
* D
*
* </pre>
*
* @param shape
* @param dir
* @param buff
* @param shape Die andere Form.
* @param dir Die Richtung.
* @param buff Der Abstand.
*/
public void alignTo( Shape shape, Options.Direction dir, double buff ) {
Point2D anchorShape = shape.getAbsAnchorPoint(dir);
@ -446,16 +631,46 @@ public abstract class Shape extends BasicDrawable {
this.y += Math.abs(dir.y) * (anchorShape.getY() - anchorThis.getY()) + dir.y * buff;
}
/**
* @param shape
* @param dir
* @see #nextTo(Shape, Options.Direction, double)
*/
public void nextTo( Shape shape, Options.Direction dir ) {
nextTo(shape, dir, DEFAULT_BUFFER);
}
/**
* Bewegt die Form neben eine andere in Richtung des angegebenen
* Ankerpunktes. Im Gegensatz zu
* {@link #moveTo(Shape, Options.Direction, double)} wird die Breite bzw.
* Höhe der Formen berücksichtigt und die Formen so platziert, dass keine
* Überlappungen vorhanden sind.
* Ankerpunktes.
* <p>
* Im Gegensatz zu {@link #moveTo(Shape, Options.Direction, double)} wird
* die Breite bzw. Höhe der Formen berücksichtigt und die Formen so
* platziert, dass keine Überlappungen vorhanden sind.
* <p>
* Befinden sich die Formen zuvor in folgender Ausrichtung:
* <pre>
*
*
* W B
*
*
* A E
*
*
* </pre>
* <p>
* bringt sie der Aufruf {@code B.nextTo(A, EAST, 0)} in diese Ausrichtung:
* <pre>
* B.nextTo(A, EAST, 0) B.nextTo(A, EAST, 10)
*
*
*
* A B A B
*
*
*
* </pre>
*
* @param shape
* @param dir
@ -469,6 +684,19 @@ public abstract class Shape extends BasicDrawable {
this.y += (anchorShape.getY() - anchorThis.getY()) + dir.y * buff;
}
@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);
}
@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);
}
/*public void shear( double dx, double dy ) {
verzerrung.shear(dx, dy);
}*/