From 080db1f4317b5e9fbad536383eb9904cc5c01c5f Mon Sep 17 00:00:00 2001 From: "J. Neugebauer" Date: Tue, 29 Nov 2022 10:12:04 +0100 Subject: [PATCH] Einige Bugfixes und Verbesserungen und ganz viel Doku --- src/main/java/schule/ngb/zm/Color.java | 108 +++++--- src/main/java/schule/ngb/zm/Constants.java | 116 ++++++++- src/main/java/schule/ngb/zm/Layer.java | 43 +++- src/main/java/schule/ngb/zm/Options.java | 241 +++++++++++++++++- src/main/java/schule/ngb/zm/Strokeable.java | 2 +- src/main/java/schule/ngb/zm/Updatable.java | 4 +- src/main/java/schule/ngb/zm/Vector.java | 4 +- .../java/schule/ngb/zm/Zeichenfenster.java | 118 ++++++++- .../java/schule/ngb/zm/Zeichenleinwand.java | 46 +++- .../java/schule/ngb/zm/Zeichenmaschine.java | 16 +- .../schule/ngb/zm/util/io/FileLoader.java | 4 +- 11 files changed, 613 insertions(+), 89 deletions(-) diff --git a/src/main/java/schule/ngb/zm/Color.java b/src/main/java/schule/ngb/zm/Color.java index 429ef25..c1394a4 100644 --- a/src/main/java/schule/ngb/zm/Color.java +++ b/src/main/java/schule/ngb/zm/Color.java @@ -112,7 +112,7 @@ public class Color implements Paint { } /** - * Erstellt eine graue Farbe entsprechend des Grauwertes gray. + * Erstellt eine graue Farbe entsprechend dem Grauwert {@code gray}. * * @param gray Ein Grauwert zwischen 0 und 255. */ @@ -121,8 +121,8 @@ public class Color implements Paint { } /** - * Erstellt eine graue Farbe entsprechend des Grauwertes gray und - * des Transparentwertes alpha. + * Erstellt eine graue Farbe entsprechend dem Grauwert {@code gray} und dem + * Transparenzwert {@code alpha}. * * @param gray Ein Grauwert zwischen 0 und 255. */ @@ -131,9 +131,9 @@ public class Color implements Paint { } /** - * Erstellt eine Farbe. Die Parameter red, green und - * blue geben die Rot-, Grün- und Blauanteile der Farbe. Die - * Werte liegen zwischen 0 und 255. + * Erstellt eine Farbe. Die Parameter {@code red}, {@code green} und + * {@code blue} geben die Rot-, Grün- und Blauanteile der Farbe. Die Werte + * liegen zwischen 0 und 255. * * @param red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. @@ -144,11 +144,11 @@ public class Color implements Paint { } /** - * Erstellt eine Farbe. Die Parameter red, green und - * blue geben die Rot-, Grün- und Blauanteile der Farbe. Die - * Werte liegen zwischen 0 und 255. - * alpha gibt den den Transparentwert an (auch zwischen - * 0 und 255), wobei 0 komplett durchsichtig ist und 255 komplett deckend. + * Erstellt eine Farbe. Die Parameter {@code red}, {@code green} und + * {@code blue} geben die Rot-, Grün- und Blauanteile der Farbe. Die Werte + * liegen zwischen 0 und 255. {@code alpha} gibt den den Transparentwert an + * (auch zwischen 0 und 255), wobei 0 komplett durchsichtig ist und 255 + * komplett deckend. * * @param red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. @@ -160,20 +160,20 @@ public class Color implements Paint { } /** - * Erstellt eine Farbe als Kopie von color. + * Erstellt eine Farbe als Kopie von {@code color}. * - * @param color + * @param color Eine Farbe. */ public Color( Color color ) { this(color.getRGBA(), true); } /** - * Erstellt eine Farbe als Kopie von color und ersetzt den - * Transparentwert durch alpha. + * Erstellt eine Farbe als Kopie von {@code color} und ersetzt den + * Transparentwert durch {@code alpha}. * - * @param color - * @param alpha + * @param color Eine Farbe. + * @param alpha Der neue Transparenzwert. */ public Color( Color color, int alpha ) { this(color.getRed(), color.getGreen(), color.getBlue(), alpha); @@ -208,18 +208,51 @@ public class Color implements Paint { /** * Erzeugt eine Farbe aus einem kodierten RGBA Integer-Wert. + *

+ * Der 32-bit Integer enthält (von rechts) in Bit 1 bis 8 den Rotwert, in + * Bit 9 bis 16 Grünwert, in Bit 17 bis 24 den Blauwert und in Bit 25 bis 32 + * den Transparenzwert der Farbe. * - * @param rgba - * @return + * @param rgba Eine RGBA-Farbe. + * @return Ein Farbobjekt. */ public static Color getRGBColor( int rgba ) { return new Color(rgba, true); } + /** + * Erzeugt eine Farbe aus Werten im + * HSB-Farbraum. + *

+ * {code h} beschreibt den Farbwert (engl. hue), {@code s} die + * Sättigung (engl. saturation) und {@code b} die absolute + * Helligkeit (engl. brightness) der Farbe. Alle Werte werden + * zwischen 0.0 und 1.0 angegeben. + * + * @param h Der Farbwert. + * @param s Die Sättigung. + * @param b Die absolute Helligkeit. + * @return Ein Farbobjekt. + * @see java.awt.Color#getHSBColor(float, float, float) + */ public static Color getHSBColor( double h, double s, double b ) { return new Color(java.awt.Color.getHSBColor((float) h, (float) s, (float) b)); } + /** + * Erzeugt eine Farbe aus Werten im + * HSL-Farbraum. + *

+ * {code h} beschreibt den Farbwert (engl. hue), {@code s} die + * Sättigung (engl. saturation) und {@code l} die relative + * Helligkeit (engl. lightness) der Farbe. Alle Werte werden + * zwischen 0.0 und 1.0 angegeben. + * + * @param h Der Farbwert. + * @param s Die Sättigung. + * @param l Die relative Helligkeit. + * @return Ein Farbobjekt. + */ public static Color getHSLColor( double h, double s, double l ) { int rgb = Color.HSLtoRGB(new float[]{(float) h, (float) s, (float) l}); return Color.getRGBColor(rgb); @@ -259,12 +292,16 @@ public class Color implements Paint { } /** - * Erzeugt eine Farbe aus einem hexadezimalen Code. Der Hexcode kann sechs- - * oder achtstellig sein (wenn ein Transparentwert vorhanden ist). Dem Code - * kann ein {@code #} Zeichen vorangestellt sein. + * Erzeugt eine Farbe aus einem hexadezimalen Code. Der Hexcode kann drei-, + * sechs- oder achtstellig sein (wenn ein Transparentwert vorhanden ist). + * Dem Code kann ein {@code #} Zeichen vorangestellt sein, muss es aber + * nicht. + *

+ * Bei einem dreistelligen Code wird jedes zeichen doppelt interpretiert. + * Das beduetet {@code #ABC} ist gleichbedeutend mit {@code #AABBCC}. * - * @param hexcode - * @return + * @param hexcode Eine Farbe als Hexcode. + * @return Ein Farbobjekt. */ public static Color parseHexcode( String hexcode ) { if( hexcode.startsWith("#") ) { @@ -301,7 +338,7 @@ public class Color implements Paint { if( color1 == null && color2 == null ) { throw new IllegalArgumentException("Color.interpolate() needs at least one color to be not null."); } - if( t < 0.0 || color2 == null ) { + if( (color1 != null && t < 0.0) || color2 == null ) { return color1.copy(); } if( t > 1.0 || color1 == null ) { @@ -351,6 +388,14 @@ public class Color implements Paint { return hsl; } + /** + * Konvertiert die Komponenten einer Farbe aus dem HSL-Farbraum in den + * RGB-Farbraum. + * + * @param hsl Die HSL-Komponenten als float-Array. + * @return Der RGBA-Farbwert. + * @see #HSLtoRGB(float[], int) + */ public static int HSLtoRGB( float[] hsl ) { return HSLtoRGB(hsl, 255); } @@ -359,9 +404,9 @@ public class Color implements Paint { * Konvertiert eine Farbe mit Komponenten im HSL-Farbraum in den * RGB-Farbraum. *

- * Die Farbkomponenten werden als Float-Array übergeben. Im Index 0 steht - * der h-Wert im Bereich 0 bis 360, Index 1 und 2 enthalten den s- und - * l-Wert im Bereich von 0 bis 1. + * Die Farbkomponenten werden als float-Array übergeben. Im Index 0 steht + * der H-Wert im Bereich 0 bis 360, Index 1 und 2 enthalten den S- und + * L-Wert im Bereich von 0 bis 1. * * @param hsl Die Farbkomponenten im HSL-Farbraum. * @param alpha Ein Transparenzwert im Bereich 0 bis 255. @@ -506,10 +551,11 @@ public class Color implements Paint { /** * Prüft, ob ein anderes Objekt zu diesem gleich ist. + *

+ * Die Methode gibt genau dann {@code true} zurück, wenn das andere Objekt + * nicht {@code null} ist, vom Typ {@code Color} ist und es dieselben Rot-, + * Grün-, Blau- und Transparenzwerte hat. * - * Die Methode gibt genau dann {@code true} zurück, wenn das andere - * Objekt nicht {@code null} ist, vom Typ {@code Color} ist und es - * dieselben Rot-, Grün-, Blau- und Transparenzwerte hat. * @param obj Das zu vergleichende Objekt. * @return {@code true}, wenn die Objekte gleich sind, sonst {@code false}. */ diff --git a/src/main/java/schule/ngb/zm/Constants.java b/src/main/java/schule/ngb/zm/Constants.java index 3dc9fa6..63a1cc9 100644 --- a/src/main/java/schule/ngb/zm/Constants.java +++ b/src/main/java/schule/ngb/zm/Constants.java @@ -1054,7 +1054,7 @@ public class Constants { } /** - * Ermittelt den Arkuskosinus der angegebenen Zahl. + * Ermittelt den Arcuskosinus der angegebenen Zahl. * * @param x Eine Zahl. * @return {@code acos(x)}. @@ -1064,7 +1064,7 @@ public class Constants { } /** - * Ermittelt den Arkusktangens der angegebenen Zahl. + * Ermittelt den Arcusktangens der angegebenen Zahl. * * @param x Eine Zahl. * @return {@code atan(x)}. @@ -1681,38 +1681,93 @@ public class Constants { } } + /** + * Konvertiert einen char-Wert in einen double-Wert. + * + * @param value Der char-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( char value ) { return value; } + /** + * Konvertiert einen byte-Wert in einen double-Wert. + * + * @param value Der byte-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( byte value ) { return value; } + /** + * Konvertiert einen short-Wert in einen double-Wert. + * + * @param value Der short-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( short value ) { return value; } + /** + * Konvertiert einen long-Wert in einen double-Wert. + * + * @param value Der long-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( long value ) { return (double) value; } + /** + * Konvertiert einen double-Wert in einen double-Wert. + * + * @param value Der double-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( double value ) { return value; } + /** + * Konvertiert einen float-Wert in einen double-Wert. + * + * @param value Der float-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( float value ) { return value; } + /** + * Konvertiert einen int-Wert in einen double-Wert. + * + * @param value Der int-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( int value ) { return value; } + /** + * Konvertiert einen boolean-Wert in einen double-Wert. + * + * @param value Der boolean-Wert. + * @return Ein double-Wert. + */ public static final double asDouble( boolean value ) { return value ? 1.0 : 0.0; } + /** + * Konvertiert einen String in einen double-Wert. + * + * @param value Der String. + * @return Ein double-Wert. + * @see Double#parseDouble(String) + */ public static final double asDouble( String value ) { try { return Double.parseDouble(value); @@ -1721,38 +1776,93 @@ public class Constants { } } + /** + * Konvertiert einen char-Wert in einen boolean-Wert. + * + * @param value Der char-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( char value ) { return value != 0; } + /** + * Konvertiert einen byte-Wert in einen boolean-Wert. + * + * @param value Der byte-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( byte value ) { return value != 0; } + /** + * Konvertiert einen short-Wert in einen boolean-Wert. + * + * @param value Der short-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( short value ) { return value != 0; } + /** + * Konvertiert einen int-Wert in einen boolean-Wert. + * + * @param value Der int-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( int value ) { return value != 0; } + /** + * Konvertiert einen long-Wert in einen boolean-Wert. + * + * @param value Der long-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( long value ) { return value != 0L; } + /** + * Konvertiert einen double-Wert in einen boolean-Wert. + * + * @param value Der double-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( double value ) { return value != 0.0; } + /** + * Konvertiert einen float-Wert in einen boolean-Wert. + * + * @param value Der float-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( float value ) { return value != 0.0f; } + /** + * Konvertiert einen boolean-Wert in einen boolean-Wert. + * + * @param value Der boolean-Wert. + * @return Ein boolean-Wert. + */ public static final boolean asBool( boolean value ) { return value; } + /** + * Konvertiert einen String in einen boolean-Wert. + * + * @param value Der String. + * @return Ein boolean-Wert. + * @see Boolean#parseBoolean(String) + */ public static final boolean asBool( String value ) { return Boolean.parseBoolean(value); } @@ -1813,7 +1923,7 @@ public class Constants { return Integer.valueOf(binary, 16); } - // Konstants für Key events (Copied from KeyEvent) + // Konstanten für Key events (Copied from KeyEvent) /** * Constant for the ENTER virtual key. diff --git a/src/main/java/schule/ngb/zm/Layer.java b/src/main/java/schule/ngb/zm/Layer.java index f59a985..5946e85 100644 --- a/src/main/java/schule/ngb/zm/Layer.java +++ b/src/main/java/schule/ngb/zm/Layer.java @@ -12,10 +12,10 @@ import java.awt.image.BufferedImage; * Die {@code Zeichenleinwand} besteht aus einer Reihe von Ebenen, die * übereinandergelegt und von "unten" nach "oben" gezeichnet werden. Die Inhalte * der oberen Ebenen können also Inhalte der darunterliegenden verdecken. - * - * Ebenen sind ein zentraler Bestandteil bei der Implementierung einer {@link Zeichenmaschine}. - * Es werden - * Sie erben von {@code Constants}, damit sie beim + *

+ * Ebenen sind ein zentraler Bestandteil bei der Implementierung einer + * {@link Zeichenmaschine}. Sie erben von {@code Constants}, da neue Ebenentypen + * von Nutzern implementiert werden können. */ public abstract class Layer extends Constants implements Drawable, Updatable { @@ -43,24 +43,39 @@ public abstract class Layer extends Constants implements Drawable, Updatable { protected boolean active = true; + /** + * Erstellt eine neue Ebene mit den Standardmaßen. + */ public Layer() { this(DEFAULT_WIDTH, DEFAULT_HEIGHT); } + /** + * Erstellt eine neue Ebene mit den angegebenen Maßen. + * + * @param width Die Breite der Ebene. + * @param height Die Höhe der Ebene. + */ public Layer( int width, int height ) { createCanvas(width, height); } + /** + * @return Die Breite der Ebene. + */ public int getWidth() { return buffer.getWidth(); } + /** + * @return Die Höhe der Ebene. + */ public int getHeight() { return buffer.getHeight(); } /** - * Ändert die Größe der Ebene auf die angegebene Größe. + * Ändert die Größe der Ebene auf die angegebenen Maße. * * @param width Die neue Breite. * @param height Die neue Höhe. @@ -88,7 +103,7 @@ public abstract class Layer extends Constants implements Drawable, Updatable { /** * Erstellt einen neuen Puffer für die Ebene und konfiguriert diesen. * - * @param width Width des neuen Puffers. + * @param width Breite des neuen Puffers. * @param height Höhe des neuen Puffers. */ private void createCanvas( int width, int height ) { @@ -115,7 +130,7 @@ public abstract class Layer extends Constants implements Drawable, Updatable { * Erstellt einen neuen Puffer für die Ebene mit der angegebenen Größe und * kopiert den Inhalt des alten Puffers in den Neuen. * - * @param width Width des neuen Puffers. + * @param width Breite des neuen Puffers. * @param height Höhe des neuen Puffers. */ private void recreateCanvas( int width, int height ) { @@ -155,14 +170,26 @@ public abstract class Layer extends Constants implements Drawable, Updatable { return visible; } + /** + * Versteckt die Ebene. + */ public void hide() { visible = false; } - public void view() { + /** + * Zeigt die Ebene an, falls sie versteckt war. + */ + @SuppressWarnings("unused") + public void show() { visible = true; } + /** + * Versteckt oder zeigt die Ebene, je nachdem, welchen Zustand sie derzeit + * hat. + */ + @SuppressWarnings("unused") public void toggle() { visible = !visible; } diff --git a/src/main/java/schule/ngb/zm/Options.java b/src/main/java/schule/ngb/zm/Options.java index 0e3370c..d170a87 100644 --- a/src/main/java/schule/ngb/zm/Options.java +++ b/src/main/java/schule/ngb/zm/Options.java @@ -11,17 +11,71 @@ public final class Options { private Options() { } + /** + * Linienstile für Konturlinien. + */ public enum StrokeType { - SOLID, DASHED, DOTTED + /** + * Durchgezogene Linien. + */ + SOLID, + + /** + * Getrichelte Linien. + */ + DASHED, + + /** + * Gepunktete Linien. + */ + DOTTED } + /** + * Stile für Pfeilspitzen. + */ public enum ArrowHead { - LINES, FILLED + /** + * Einfache Pfeilspitze aus zwei Linien. + */ + LINES, + + /** + * Gefülltes Dreieck. + */ + FILLED } + /** + * Arten von Bögen. + *

+ * Die Werte legen fest, wie Bögen geschlossen werden sollen, wenn sie + * beispielsweise gefüllt werden. + *

+ * Wrapper für die AWT-Konstanten in {@link Arc2D}. + */ public enum PathType { - OPEN(Arc2D.OPEN), CLOSED(Arc2D.CHORD), PIE(Arc2D.PIE); + /** + * Offener Pfad, bei dem die Pfadenden direkt miteinander verbunden + * werden ohne eine Linie zu ziehen. + */ + OPEN(Arc2D.OPEN), + /** + * Geschlossener Pfad, bei dem die Pfadenden direkt miteinander + * verbunden werden, indem eine Linie gezogen wird. + */ + CLOSED(Arc2D.CHORD), + + /** + * Geschlossener Pfad, bei dem Linien von den Pfadenden zum Mittelpunkt + * des Kreises, der den Kreisbogen festlegt, gezogen werden. + */ + PIE(Arc2D.PIE); + + /** + * Der entsprechende Wert der Konstanten in {@link Arc2D} + */ public final int awt_type; PathType( int type ) { @@ -33,25 +87,100 @@ public final class Options { * Zustände in denen sich die Zeichenmaschine befinden kann. */ public enum AppState { + /** + * Die Zeichenmaschine befindet sich in der Initialisierung. Die + * Laufzeitumgebung wird konfiguriert und alle nötigen Komonenten + * ({@link Zeichenfenster}, {@link Zeichenleinwand}, ...) werden + * erstellt. + */ INITIALIZING, + + /** + * Die Initialisierung der Zeichenmaschine ist beendet, aber der + * {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * wurde noch nicht gestartet. + */ INITIALIZED, + + /** + * Die Zeichenmaschine wurde gestartet und der + * {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * arbeitet. + */ RUNNING, + + /** + * Der {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * wurde pausiert. + */ PAUSED, + + /** + * Der {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * wurde gestoppt, die Zeichenmaschine ist aber noch nicht vollständig + * heruntergefahren und hat noch nicht alle Ressourcen freigegeben. + */ STOPPED, + + /** + * Der {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * ist beendet. + */ TERMINATED, + + /** + * Die Zeichenmaschine ist dabei, vollständig herunterzufahren und alle + * Ressourcen freizugeben. + */ QUITING, + + /** + * Der {@link schule.ngb.zm.Zeichenmaschine.Zeichenthread Zeichenthread} + * wartet gerade auf den nächsten Frame. + */ IDLE, + + /** + * Die Zeichenmaschine führt gerade + * {@link Zeichenmaschine#update(double)} aus. + */ UPDATING, + + /** + * Die Zeichenmaschine führt gerade {@link Zeichenmaschine#draw()} aus. + */ DRAWING, + + /** + * Die Ausführung der Zeichenmaschine wurde mit + * {@link Zeichenmaschine#delay(int)} verzögert und wartet auf + * Fortsetzung. + */ DELAYED, + + /** + * Die Zeichenmaschine sendet gereade gesammelte Events und führt Tasks + * aus. + */ DISPATCHING } /** * Richtungen für die Ausrichtung von Formen. Richtungen sind durch - * Einheitsvektoren bzw. deren Kombination repräsentiert, wodurch mit ihnen - * gerechnet werden kann. Jede Richtung ist zusätzlich als Himmelsrichtung - * definiert. + * Einheitsvektoren bzw. deren Kombination im Koordinatensystem der + * Zeichenfläche repräsentiert, wodurch mit ihnen gerechnet werden kann. Die + * Richtung {@link #DOWN} ist beispielsweise gleich {@code (1, 0)}. + *

+ * Jede Richtung ist zusätzlich als Himmelsrichtung definiert. {@link #EAST} + * ist äquivalent zu {@link #RIGHT} als {@code (0, 1)} definiert. Auch wenn + * beide Werte dieselbe Richtung beschreiben sind sie nicht "gleich" + * ({@code EAST != RIGHT}). Um verschiedene Richtungen zuverlässig zu + * vergleichen, sollte daher {@link #equals(Direction)} verwendet werden. + *

+ * Für zusammengesetzten Richtungen wie {@link #NORTHEAST} bzw + * {@link #UPRIGHT} lassen sich mit {@link #in(Direction)} und + * {@link #contains(Direction)} Beziehungen zu den anderen Richtungen + * prüfen. Beispielsweise ist {@code NORTHEAST.contains(NORTH)} wahr. */ public enum Direction { CENTER(0, 0), @@ -89,30 +218,116 @@ public final class Options { this.y = original.y; } + /** + * Prüft, ob die angegebene Richtung gleich dieser ist. Dabei werden die + * Komponenten des Richtungsvektors geprüft. Daher sind für die Methode + * beispielsweise {@link #NORTH} und {@link #UP} gleich. + * + * @param dir Eine andere Richtung. + * @return {@code true}, wenn die Richtungen dieselben Komponenten + * haben, {@code false} sonst. + */ + public boolean equals( Direction dir ) { + return this.x == dir.x && this.y == dir.y; + } + + /** + * Prüft, ob diese Richtung Tile der angegebenen Richtung ist. + *

+ * Beispielsweise ist {@link #NORTH} Teil von {@link #NORTHWEST}, aber + * nicht von {@link #SOUTHWEST}. Dabei wird doe Art der Richtung nicht + * beachtet. {@link #UP} ist daher auch Teil von {@link #NORTHWEST}. + * + *

+		 * NORTH.in(NORTHWEST) // true
+		 * NORTH.in(SOUTHWEST) // false
+		 * UP.in(NORTHWEST) // true
+		 * 
+ * + * @param dir Eine andere Richtung. + * @return {@code true}, wenn diese Richtungen Teil der anderen ist, + * {@code false} sonst. + */ public boolean in( Direction dir ) { return (this.x == dir.x && this.y == 0) || (this.y == dir.y && this.x == 0) || (this.x == dir.x && this.y == dir.y); } + /** + * Prüft, ob die angegebene Richtung Teil dieser Richtung ist. + *

+ * Beispielsweise ist {@link #NORTH} Teil von {@link #NORTHWEST}, aber + * nicht von {@link #SOUTHWEST}. Dabei wird die Art der Richtung nicht + * beachtet. {@link #UP} ist daher auch Teil von {@link #NORTHWEST}. + * + *

+		 * NORTHWEST.contains(NORTH) // true
+		 * SOUTHWEST.in(NORTH) // false
+		 * NORTHWEST.in(UP) // true
+		 * 
+ * + * @param dir Eine andere Richtung. + * @return {@code true}, wenn diese Richtungen Teil der anderen ist, + * {@code false} sonst. + */ public boolean contains( Direction dir ) { return dir.in(this); } + /** + * @return Diese Richtung als Vektor-Objekt. + */ public Vector asVector() { return new Vector(x, y); } /** - * Gibt die entgegengesetzte Richtung zu dieser zurück. + * Liefert die entgegengesetzte Richtung zu dieser. + *

+ * Es wird die Art der Richtung berücksichtigt. Das bedeutet, das + * Inverse von {@link #UP} ist {@link #DOWN}, während das Inverse von + * {@link #NORTH} zu {@link #SOUTH} wird. * - * @return + * @return Die entgegengesetzte Richtung zu dieser. */ public Direction inverse() { - for( Direction dir : Direction.values() ) { - if( dir.x == -this.x && dir.y == -this.y ) { - return dir; - } + switch( this ) { + case UP: + return DOWN; + case DOWN: + return UP; + case LEFT: + return RIGHT; + case RIGHT: + return LEFT; + case UPLEFT: + return DOWNRIGHT; + case UPRIGHT: + return DOWNLEFT; + case DOWNLEFT: + return UPRIGHT; + case DOWNRIGHT: + return UPLEFT; + case MIDDLE: + return MIDDLE; + case NORTH: + return SOUTH; + case SOUTH: + return NORTH; + case EAST: + return WEST; + case WEST: + return EAST; + case SOUTHWEST: + return NORTHEAST; + case SOUTHEAST: + return NORTHWEST; + case NORTHEAST: + return SOUTHWEST; + case NORTHWEST: + return SOUTHEAST; + default: + return CENTER; } - return CENTER; } } diff --git a/src/main/java/schule/ngb/zm/Strokeable.java b/src/main/java/schule/ngb/zm/Strokeable.java index 48db51f..36b0e29 100644 --- a/src/main/java/schule/ngb/zm/Strokeable.java +++ b/src/main/java/schule/ngb/zm/Strokeable.java @@ -15,7 +15,7 @@ import java.awt.Stroke; * {@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 + * Konturlinien zur verfügung zu stellen. Allerdings sollte davon nach * Möglichkeit zugunsten einer einheitlichen API abgesehen werden. *

* Das Äquivalent für Füllungen stellt {@link Fillable} dar. diff --git a/src/main/java/schule/ngb/zm/Updatable.java b/src/main/java/schule/ngb/zm/Updatable.java index 94eb76e..c519626 100644 --- a/src/main/java/schule/ngb/zm/Updatable.java +++ b/src/main/java/schule/ngb/zm/Updatable.java @@ -28,7 +28,7 @@ public interface Updatable { * @return {@code true}, wenn das Objekt aktiv ist, {@code false} * andernfalls. */ - public boolean isActive(); + boolean isActive(); /** * Änderung des Zustandes des Objekts abhängig vom Zeitintervall @@ -39,6 +39,6 @@ public interface Updatable { * * @param delta Zeitintervall seit dem letzten Aufruf (in Sekunden). */ - public void update( double delta ); + void update( double delta ); } diff --git a/src/main/java/schule/ngb/zm/Vector.java b/src/main/java/schule/ngb/zm/Vector.java index 5ea67c2..67f3aaa 100644 --- a/src/main/java/schule/ngb/zm/Vector.java +++ b/src/main/java/schule/ngb/zm/Vector.java @@ -422,8 +422,8 @@ public class Vector extends Point2D.Double { * dem quadrierten Abstand durchführen, wenn auch die gewünschte Entfernung * quadriert wird. * - * @param vector - * @return + * @param vector Ein anderer Vektor. + * @return Das Quadrat der Entfernung zum anderen Vektor. */ public double distanceSq( Vector vector ) { return super.distanceSq(vector); diff --git a/src/main/java/schule/ngb/zm/Zeichenfenster.java b/src/main/java/schule/ngb/zm/Zeichenfenster.java index 95f28ef..2e6fb87 100644 --- a/src/main/java/schule/ngb/zm/Zeichenfenster.java +++ b/src/main/java/schule/ngb/zm/Zeichenfenster.java @@ -9,9 +9,7 @@ import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.io.File; import java.io.IOException; -import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; @@ -25,6 +23,12 @@ import java.util.ArrayList; */ public class Zeichenfenster extends JFrame { + /** + * Setzt das Look and Feel auf den Standard des Systems. + *

+ * Sollte einmalig vor erstellen des erstyen Programmfensters aufgerufen + * werden. + */ public static final void setLookAndFeel() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); @@ -33,6 +37,17 @@ public class Zeichenfenster extends JFrame { } } + /** + * Ermittelt ein {@link GraphicsDevice Anzeigegerät}, auf dem ein neues + * Zeichenfenster angezeigt werden soll. In der Regel ist dies der + * Bildschirm, auf dem sich derzeit der Mauszeiger befindet. Kann kein + * solcher Bildschirm ermittelt werden, wird das + * {@link GraphicsEnvironment#getDefaultScreenDevice() Standardgerät} + * zurückgegeben. + * + * @return Das Anzeigegerät, auf dem ein neues Fenster angezeigt werden + * sollte. + */ public static final GraphicsDevice getGraphicsDevice() { // Wir suchen den Bildschirm, der derzeit den Mauszeiger enthält, um // das Zeichenfenster dort zu zentrieren. @@ -55,10 +70,10 @@ public class Zeichenfenster extends JFrame { } /** - * Das Anzeigefenster, auf dem die ZM gestartet wurde (muss nicht gleich dem - * Aktuellen sein, wenn das Fenster verschoben wurde). + * Das Anzeigegerät, auf dem die Zeichenmaschine gestartet wurde (muss nicht + * gleich dem Aktuellen sein, wenn das Fenster verschoben wurde). */ - private GraphicsDevice displayDevice; + private final GraphicsDevice displayDevice; /** * Bevorzugte Abmessungen der Zeichenleinwand. Für das Zeichenfenster hat es @@ -90,20 +105,56 @@ public class Zeichenfenster extends JFrame { } }; - private Zeichenleinwand canvas; + // Die Zeichenleinwand dieses Fensters. + private final Zeichenleinwand canvas; + /** + * Erstellt ein neues Zeichenfenster mit dem angegebenen Titel und einer + * {@link Zeichenleinwand} in der angegebenen Größe. + * + * @param width Die Breite der Zeichenleinwand. + * @param height Die Höhe der Zeichenleinwand. + * @param title Der Titel des Fensters. + */ + @SuppressWarnings( "unused" ) public Zeichenfenster( int width, int height, String title ) { this(new Zeichenleinwand(width, height), title, getGraphicsDevice()); } + /** + * Erstellt ein neues Zeichenfenster mit dem angegebenen Titel und einer + * {@link Zeichenleinwand} in der angegebenen Größe auf dem angegebenen + * Anzeigegerät. + * + * @param width Die Breite der Zeichenleinwand. + * @param height Die Höhe der Zeichenleinwand. + * @param title Der Titel des Fensters. + * @param displayDevice Das Anzeigegerät für das Fenster. + */ + @SuppressWarnings( "unused" ) public Zeichenfenster( int width, int height, String title, GraphicsDevice displayDevice ) { this(new Zeichenleinwand(width, height), title, displayDevice); } + /** + * Erstellt ein neues Zeichenfenster mit dem angegebenen Titel und der + * angegebene {@link Zeichenleinwand}. + * + * @param canvas Die Zeichenleinwand. + * @param title Der Titel des Fensters. + */ public Zeichenfenster( Zeichenleinwand canvas, String title ) { this(canvas, title, getGraphicsDevice()); } + /** + * Erstellt ein neues Zeichenfenster mit dem angegebenen Titel und der + * angegebene {@link Zeichenleinwand} auf dem angegebenen Anzeigegerät. + * + * @param canvas Die Zeichenleinwand. + * @param title Der Titel des Fensters. + * @param displayDevice Das Anzeigegerät für das Fenster. + */ public Zeichenfenster( Zeichenleinwand canvas, String title, GraphicsDevice displayDevice ) { super(Validator.requireNotNull(displayDevice).getDefaultConfiguration()); this.displayDevice = displayDevice; @@ -124,14 +175,19 @@ public class Zeichenfenster extends JFrame { try { if( Zeichenmaschine.MACOS ) { URL iconUrl = Zeichenmaschine.class.getResource("icon_512.png"); - Image icon = ImageIO.read(iconUrl); - // Dock Icon in macOS setzen - Taskbar taskbar = Taskbar.getTaskbar(); - taskbar.setIconImage(icon); + if( iconUrl != null ) { + Image icon = ImageIO.read(iconUrl); + // Dock Icon in macOS setzen + Taskbar taskbar = Taskbar.getTaskbar(); + taskbar.setIconImage(icon); + } } else { ArrayList icons = new ArrayList<>(4); - for( int size: new int[]{32, 64, 128, 512} ) { - icons.add(ImageIO.read(new File("icon_" + size + ".png"))); + for( int size : new int[]{32, 64, 128, 512} ) { + URL icnUrl = Zeichenmaschine.class.getResource("icon_" + size + ".png"); + if( icnUrl != null ) { + icons.add(ImageIO.read(icnUrl)); + } } this.setIconImages(icons); @@ -150,19 +206,45 @@ public class Zeichenfenster extends JFrame { // this.centerFrame(); } + /** + * Liefert das Anzeigegerät, auf dem dieses Fenster erstellt wurde. + *

+ * Das Anzeigegerät muss nicht unbedingt gleich dem sein, auf dem sich das + * Fenster derzeit befindet, wenn das Fenster verschoben wurde. + * + * @return Das Anzeigegerät. + */ + @SuppressWarnings( "unused" ) public GraphicsDevice getDisplayDevice() { return displayDevice; } + /** + * Liefert die Abmessungen des Anzeigegeräts, auf dem das Fenster gestartet + * wurde. + * + * @return Die Abmessungen des Anzeigegeräts. + */ public Rectangle getScreenBounds() { // return GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); return displayDevice.getDefaultConfiguration().getBounds(); } + /** + * Liefert die Zeichenleinwand dieses Fensters. + * + * @return Die Zeichenleinwand. + */ + @SuppressWarnings( "unused" ) public Zeichenleinwand getCanvas() { return canvas; } + /** + * Liefert die Abmessungen der Zeichenleinwand zurück. + * + * @return Die Abmessungen der Zeichenleinwand. + */ public Rectangle getCanvasBounds() { return canvas.getBounds(); } @@ -179,6 +261,12 @@ public class Zeichenfenster extends JFrame { ); } + /** + * Setzt die Größe der Zeichenleinwand auf die angegebenen Werte. + * + * @param newWidth Neue Breite der Zeichenleinwand. + * @param newHeight Neue Höhe der Zeichenleinwand. + */ public void setCanvasSize( int newWidth, int newHeight ) { // TODO: (ngb) Put constrains on max/min frame/canvas size if( fullscreen ) { @@ -259,6 +347,12 @@ public class Zeichenfenster extends JFrame { } } + /** + * Prüft, ob sich dieses Zeichenfenster im Vollbild befindet. + * + * @return {@code true}, wenn das Fenster im Vollbild ist, {@code false} + * sonst. + */ public boolean isFullscreen() { Window win = displayDevice.getFullScreenWindow(); return fullscreen && win.equals(this); diff --git a/src/main/java/schule/ngb/zm/Zeichenleinwand.java b/src/main/java/schule/ngb/zm/Zeichenleinwand.java index c2eaf72..f46ef1e 100644 --- a/src/main/java/schule/ngb/zm/Zeichenleinwand.java +++ b/src/main/java/schule/ngb/zm/Zeichenleinwand.java @@ -1,6 +1,5 @@ package schule.ngb.zm; -import schule.ngb.zm.layers.ColorLayer; import schule.ngb.zm.util.Log; import java.awt.Canvas; @@ -8,7 +7,10 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Toolkit; import java.awt.image.BufferStrategy; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; /** * Eine Leinwand ist die Hauptkomponente einer Zeichenmaschine. Sie besteht aus @@ -22,13 +24,13 @@ import java.util.*; */ public class Zeichenleinwand extends Canvas { + // Lokales Lock für Rendervorgänge. private final Object[] renderLock = new Object[0]; - /** - * Liste der hinzugefügten Ebenen. - */ + // Liste der hinzugefügten Ebenen. private final List layers; + // Status der Zeichenleinwand. private boolean rendering = false, suspended = false; /** @@ -80,6 +82,10 @@ public class Zeichenleinwand extends Canvas { } } + /** + * Setzt das Zeichnen der Leinwand fort, falls es zuvor mit + * {@link #suspendRendering()} ausgesetzt wurde. + */ public void resumeRendering() { suspended = false; } @@ -201,6 +207,7 @@ public class Zeichenleinwand extends Canvas { * @param Typ der Ebenen, die abgefragt werden. * @return Eine Liste mit den vorhandenen Ebenen des abgefragten Typs. */ + @SuppressWarnings( "unused" ) public List getLayers( Class type ) { ArrayList result = new ArrayList<>(layers.size()); synchronized( layers ) { @@ -213,10 +220,24 @@ public class Zeichenleinwand extends Canvas { return result; } + /** + * Entfernt die angegebene Ebene von dieser Zeichenleinwand. + * + * @param pLayer Die Ebene, die entfernt werden soll. + * @return {@code true}, wenn die Liste vorhanden war und entfernt wurde, + * {@code false} sonst. + */ + @SuppressWarnings( "unused" ) public boolean removeLayer( Layer pLayer ) { return layers.remove(pLayer); } + /** + * Entfernt alle angegebenen Ebenen von dieser Zeichenleinwand. + * + * @param removeLayers Die Ebenen, die entfernt werden sollen. + */ + @SuppressWarnings( "unused" ) public void removeLayers( Layer... removeLayers ) { synchronized( layers ) { for( Layer layer : removeLayers ) { @@ -225,10 +246,21 @@ public class Zeichenleinwand extends Canvas { } } + /** + * Entfernt alle vorhandenen Ebenen von dieser Zeichenleinwand. + */ + @SuppressWarnings( "unused" ) public void clearLayers() { layers.clear(); } + /** + * Aktualisiert alle {@link Layer Ebenen}, die dieser Zeichenleinwand + * hinzugefügt wurden. + * + * @param delta Die Zeit seit dem letzten Aufruf in Sekunden. + * @see Layer#update(double) + */ public void updateLayers( double delta ) { synchronized( layers ) { for( Layer layer : List.copyOf(layers) ) { @@ -261,9 +293,9 @@ public class Zeichenleinwand extends Canvas { } /** - * Zeichnet den Inhalt aller {@link Layer Ebenen} in den Grafik-Kontext. + * Zeichnet den Inhalt aller {@link Layer Ebenen} in den Grafikkontext. * - * @param graphics + * @param graphics Der Grafikkontext. */ public void draw( Graphics graphics ) { Graphics2D g2d = (Graphics2D) graphics.create(); diff --git a/src/main/java/schule/ngb/zm/Zeichenmaschine.java b/src/main/java/schule/ngb/zm/Zeichenmaschine.java index e372e60..02b3aeb 100644 --- a/src/main/java/schule/ngb/zm/Zeichenmaschine.java +++ b/src/main/java/schule/ngb/zm/Zeichenmaschine.java @@ -679,9 +679,9 @@ public class Zeichenmaschine extends Constants { * Gibt die erste (unterste) {@link Layer Ebene} der angegebenen Klasse * zurück. * - *

-	 *     DrawingLayer draw = getLayer(DrawingLayer.class);
-	 * 
+ *

+	 * DrawingLayer draw = getLayer(DrawingLayer.class);
+	 * 
* * @param layerClass * @param @@ -947,9 +947,9 @@ public class Zeichenmaschine extends Constants { *

* Die Konstanten der Klasse {@link Cursor} definieren 13 Standardzeiger, * die durch angabe der Nummer geladen werden können. - *

-	 *     setCursor(Cursor.HAND_CURSOR);
-	 * 
+ *

+	 * setCursor(Cursor.HAND_CURSOR);
+	 * 
* * @param pPredefinedCursor Eine der Cursor-Konstanten. * @see Cursor @@ -1022,9 +1022,9 @@ public class Zeichenmaschine extends Constants { * {@code delta} wird in Sekunden angegeben. Um eine Form zum Beispiel um * {@code 50} Pixel pro Sekunde in {@code x}-Richtung zu bewegen, kann so * vorgegangen werden: - *
+	 * 

 	 * shape.move(50*delta, 0.0);
-	 * 
+ *
* * @param delta */ diff --git a/src/main/java/schule/ngb/zm/util/io/FileLoader.java b/src/main/java/schule/ngb/zm/util/io/FileLoader.java index 4454476..17fc59e 100644 --- a/src/main/java/schule/ngb/zm/util/io/FileLoader.java +++ b/src/main/java/schule/ngb/zm/util/io/FileLoader.java @@ -30,7 +30,7 @@ public final class FileLoader { } /** - * Lädt die angegebene Datei Zeilenweise in ein Array. + * Lädt die angegebene Datei Zeilenweise in eine Liste. * * @param source * @param charset @@ -161,7 +161,7 @@ public final class FileLoader { ).toArray(double[][]::new); } - public FileLoader() { + private FileLoader() { } private static final Log LOG = Log.getLogger(FileLoader.class);