From 740bb37279bd83698850d60db62a251382427b05 Mon Sep 17 00:00:00 2001 From: "J. Neugebauer" Date: Tue, 12 Jul 2022 23:22:35 +0200 Subject: [PATCH] Klasse Constants kommentiert und refactored --- src/main/java/schule/ngb/zm/Color.java | 88 +- src/main/java/schule/ngb/zm/Constants.java | 809 ++++++++++++++---- src/main/java/schule/ngb/zm/Options.java | 7 +- .../java/schule/ngb/zm/Zeichenleinwand.java | 6 +- .../java/schule/ngb/zm/Zeichenmaschine.java | 26 +- src/main/java/schule/ngb/zm/shapes/Shape.java | 2 +- src/main/java/schule/ngb/zm/util/Noise.java | 308 +++++++ .../java/schule/ngb/zm/util/Validator.java | 35 +- .../java/schule/ngb/zm/ConstantsTest.java | 32 +- .../java/schule/ngb/zm/TestAttraction.java | 4 +- src/test/java/schule/ngb/zm/TestShapes.java | 3 +- 11 files changed, 1086 insertions(+), 234 deletions(-) create mode 100644 src/main/java/schule/ngb/zm/util/Noise.java diff --git a/src/main/java/schule/ngb/zm/Color.java b/src/main/java/schule/ngb/zm/Color.java index 33c2033..578433f 100644 --- a/src/main/java/schule/ngb/zm/Color.java +++ b/src/main/java/schule/ngb/zm/Color.java @@ -3,17 +3,15 @@ package schule.ngb.zm; /** * Repräsentiert eine Farbe in der Zeichenmaschine. *

- * Farben bestehen entweder aus einem Grauwert (zwischen 0 und - * 255) oder einem Rot-, Grün- und Blauanteil (jeweils zwischen - * 0 und 255). + * Farben bestehen entweder aus einem Grauwert (zwischen 0 und 255) oder einem + * Rot-, Grün- und Blauanteil (jeweils zwischen 0 und 255). *

- * Eine Farbe hat außerdem einen Transparenzwert zwischen 0 - * (unsichtbar) und 255 (deckend). + * Eine Farbe hat außerdem einen Transparenzwert zwischen 0 (unsichtbar) und 255 + * (deckend). */ public class Color { - //@formatter:off /** * Die Farbe Schwarz (Grauwert 0). @@ -124,12 +122,12 @@ public class Color { /** * 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. + * 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 red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. - * @param blue Blauwert zwischen 0 und 255. + * @param blue Blauwert zwischen 0 und 255. */ public Color( int red, int green, int blue ) { this(red, green, blue, 255); @@ -137,16 +135,14 @@ public class Color { /** * 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. + * 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. + * 0 und 255), wobei 0 komplett durchsichtig ist und 255 komplett deckend. * - * @param red Rotwert zwischen 0 und 255. + * @param red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. - * @param blue Blauwert zwischen 0 und 255. + * @param blue Blauwert zwischen 0 und 255. * @param alpha Transparentwert zwischen 0 und 255. */ public Color( int red, int green, int blue, int alpha ) { @@ -184,10 +180,11 @@ public class Color { /** * Interner Konstruktor für die Initialisierung einer Farbe mit einem * RGBA-Wert. - * + *

* Da der Konstruktor {@link #Color(int)} schon besetzt ist, muss hier der - * Parameter {@code isRGBA} auf {@code true} gesetzt werden, damit {@code rgba} - * korrekt interpretiert wird. + * Parameter {@code isRGBA} auf {@code true} gesetzt werden, damit + * {@code rgba} korrekt interpretiert wird. + * * @param rgba RGBA-wert der Farbe. * @param isRGBA Sollte immer {@code true} sein. */ @@ -210,12 +207,12 @@ public class Color { return c; } - public static Color getHSBColor(double h, double s, double b) { - return new Color(java.awt.Color.getHSBColor((float)h, (float)s, (float)b)); + public static Color getHSBColor( double h, double s, double b ) { + return new Color(java.awt.Color.getHSBColor((float) h, (float) s, (float) b)); } - public static Color getHSLColor(double h, double s, double l) { - int rgb = Color.HSLtoRGB(new float[]{(float)h, (float)s, (float)l}); + 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); } @@ -235,9 +232,9 @@ public class Color { } /** - * 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 sechs- + * oder achtstellig sein (wenn ein Transparentwert vorhanden ist). Dem Code + * kann ein {@code #} Zeichen vorangestellt sein. * * @param hexcode * @return @@ -336,10 +333,11 @@ public class Color { /** * 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. + * * @param hsl Die Farbkomponenten im HSL-Farbraum. * @param alpha Ein Transparenzwert im Bereich 0 bis 255. * @return Der RGBA-Wert der Farbe. @@ -392,6 +390,7 @@ public class Color { /** * Erzeugt eine Kopie dieser Farbe. + * * @return Ein neues Farbobjekt. */ public Color copy() { @@ -400,10 +399,11 @@ public class Color { /** * Gibt den RGBA-Wert dieser Farbe zurück. - * - * Eine Farbe wird als 32-Bit Integer gespeichert. Bits 24-31 enthalten - * den Transparenzwert, 16-23 den Rotwert, 8-15 den Grünwert und 0-7 den + *

+ * Eine Farbe wird als 32-Bit Integer gespeichert. Bits 24-31 enthalten den + * Transparenzwert, 16-23 den Rotwert, 8-15 den Grünwert und 0-7 den * Blauwert der Farbe. + * * @return Der RGBA-Wert der Farbe. * @see #getRed() * @see #getGreen() @@ -416,6 +416,7 @@ public class Color { /** * Gibt den Rotwert dieser Farbe zurück. + * * @return Der Rotwert der Farbe zwischen 0 und 255. */ public int getRed() { @@ -424,6 +425,7 @@ public class Color { /** * Gibt den Grünwert dieser Farbe zurück. + * * @return Der Grünwert der Farbe zwischen 0 und 255. */ public int getGreen() { @@ -432,6 +434,7 @@ public class Color { /** * Gibt den Blauwert dieser Farbe zurück. + * * @return Der Blauwert der Farbe zwischen 0 und 255. */ public int getBlue() { @@ -440,6 +443,7 @@ public class Color { /** * Gibt den Transparenzwert dieser Farbe zurück. + * * @return Der Transparenzwert der Farbe zwischen 0 und 255. */ public int getAlpha() { @@ -448,9 +452,10 @@ public class Color { /** * Erzeugt ein {@link java.awt.Color}-Objekt aus dieser Farbe. + *

+ * Das erzeugte Farbobjekt hat dieselben Rot-, Grün-, Blau- und + * Transparenzwerte wie diese Farbe. * - * Das erzeugte Farbobjekt hat dieselben Rot-, Grün-, Blau- - * und Transparenzwerte wie diese Farbe. * @return Ein Java-Farbobjekt. */ public java.awt.Color getJavaColor() { @@ -468,11 +473,12 @@ public class Color { * @return {@code true}, wenn die Objekte gleich sind, sonst {@code false}. */ public boolean equals( Object obj ) { - return obj instanceof Color && ((Color)obj).getRGBA() == this.rgba; + return obj instanceof Color && ((Color) obj).getRGBA() == this.rgba; } /** * Erzeugt einen Text-String, der diese Farbe beschreibt. + * * @return Eine Textversion der Farbe. */ @Override @@ -482,6 +488,7 @@ public class Color { /** * Berechnet einen Hashcode für dieses Farbobjekt. + * * @return Ein Hashcode für diese Rabe. */ @Override @@ -490,7 +497,8 @@ public class Color { } /** - * Erzeugt eine um 30% hellere Version dieser Farbe. + * Erzeugt eine um 30% hellere Version dieser Farbe. + * * @return Ein Farbobjekt mit einer helleren Farbe. */ public Color brighter() { @@ -499,6 +507,7 @@ public class Color { /** * Erzeugt eine um {@code percent} hellere Version dieser Farbe. + * * @param percent Eine Prozentzahl zwischen 0 und 100. * @return Ein Farbobjekt mit einer helleren Farbe. */ @@ -510,6 +519,7 @@ public class Color { /** * Erzeugt eine um 30% dunklere Version dieser Farbe. + * * @return Ein Farbobjekt mit einer dunkleren Farbe. */ public Color darker() { @@ -518,6 +528,7 @@ public class Color { /** * Erzeugt eine um {@code percent} dunklere Version dieser Farbe. + * * @param percent Eine Prozentzahl zwischen 0 und 100. * @return Ein Farbobjekt mit einer dunkleren Farbe. */ @@ -528,11 +539,12 @@ public class Color { } public Color greyscale() { - return new Color((int)(getRed()*.299 + getGreen()*.587 + getBlue()*0.114)); + return new Color((int) (getRed() * .299 + getGreen() * .587 + getBlue() * 0.114)); } /** * Erzeugt eine zu dieser invertierte Farbe. + * * @return Ein Farbobjekt mit der invertierten Farbe. */ public Color inverted() { @@ -542,6 +554,7 @@ public class Color { /** * Erzeugt die Komplementärfarbe zu dieser. + * * @return Ein Farbobjekt mit der Komplementärfarbe. */ public Color complement() { @@ -554,11 +567,12 @@ public class Color { * Wählt entweder {@link #WHITE weiß} oder {@link #BLACK schwarz} aus, je * nachdem, welche der Farben besser als Textfarbe mit dieser Farbe als * Hintergrund funktioniert (besser lesbar ist). + * * @return Schwarz oder weiß. */ public Color textcolor() { // Basiert auf https://stackoverflow.com/questions/946544/good-text-foreground-color-for-a-given-background-color - if( (getRed()*.299 + getGreen()*.587 + getBlue()*0.114) < 186 ) { + if( (getRed() * .299 + getGreen() * .587 + getBlue() * 0.114) < 186 ) { return WHITE; } else { return BLACK; diff --git a/src/main/java/schule/ngb/zm/Constants.java b/src/main/java/schule/ngb/zm/Constants.java index 561b3aa..a22bb6a 100644 --- a/src/main/java/schule/ngb/zm/Constants.java +++ b/src/main/java/schule/ngb/zm/Constants.java @@ -1,6 +1,7 @@ package schule.ngb.zm; import schule.ngb.zm.util.ImageLoader; +import schule.ngb.zm.util.Noise; import java.awt.Cursor; import java.awt.event.KeyEvent; @@ -8,6 +9,7 @@ import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.Random; +@SuppressWarnings( "unused" ) public class Constants { /** @@ -76,162 +78,287 @@ public class Constants { */ public static final int STD_BUFFER = 10; + /** + * Option für durchgezogene Konturen und Linien. + */ public static final Options.StrokeType SOLID = Options.StrokeType.SOLID; + /** + * Option für gestrichelte Konturen und Linien. + */ public static final Options.StrokeType DASHED = Options.StrokeType.DASHED; + /** + * Option für gepunktete Konturen und Linien. + */ public static final Options.StrokeType DOTTED = Options.StrokeType.DOTTED; + /** + * Option für Pfeile mit Strichen als Kopf. + */ public static final Options.ArrowHead LINES = Options.ArrowHead.LINES; + /** + * Option für Pfeile mit gefüllten Köpfen. + */ public static final Options.ArrowHead FILLED = Options.ArrowHead.FILLED; + /** + * Option für den Abschluss eines Pfades oder Bogens, ohne die Enden zu + * verbinden. + */ public static final Options.PathType OPEN = Options.PathType.OPEN; + /** + * Option für den Abschluss eines Pfades oder Bogens durch Verbindung der + * Enden des Bogens mit einer Linie. + */ public static final Options.PathType CLOSED = Options.PathType.CLOSED; + /** + * Option für den Abschluss eines Bogens durch Verbindung der Enden des + * Bogens mit dem Mittelpunkt der zugrundeliegenden Ellipse. Dadurch + * entsteht ein Kreisausschnitt. + */ public static final Options.PathType PIE = Options.PathType.PIE; + /** + * Richtung: Mitte (bzw. keine Richtung) + */ public static final Options.Direction CENTER = Options.Direction.CENTER; + /** + * Richtung: Norden + * + * @see #UP + */ public static final Options.Direction NORTH = Options.Direction.NORTH; + /** + * Richtung: Osten + * + * @see #RIGHT + */ public static final Options.Direction EAST = Options.Direction.EAST; + /** + * Richtung: Süden + * + * @see #DOWN + */ public static final Options.Direction SOUTH = Options.Direction.SOUTH; + /** + * Richtung: Westen + * + * @see #LEFT + */ public static final Options.Direction WEST = Options.Direction.WEST; + /** + * Richtung: Nordosten + * + * @see #UPLEFT + */ public static final Options.Direction NORTHEAST = Options.Direction.NORTHEAST; + /** + * Richtung: Südosten + * + * @see #DOWNLEFT + */ public static final Options.Direction SOUTHEAST = Options.Direction.SOUTHEAST; + /** + * Richtung: Nordwesten + * + * @see #UPRIGHT + */ public static final Options.Direction NORTHWEST = Options.Direction.NORTHWEST; + /** + * Richtung: Südwesten + * + * @see #DOWNRIGHT + */ public static final Options.Direction SOUTHWEST = Options.Direction.SOUTHWEST; + /** + * Richtung: Mitte + * + * @see #CENTER + */ public static final Options.Direction MIDDLE = Options.Direction.MIDDLE; + /** + * Richtung: Oben + * + * @see #NORTH + */ public static final Options.Direction UP = Options.Direction.UP; + /** + * Richtung: Rechts + * + * @see #EAST + */ public static final Options.Direction RIGHT = Options.Direction.RIGHT; + /** + * Richtung: Unten + * + * @see #SOUTH + */ public static final Options.Direction DOWN = Options.Direction.DOWN; + /** + * Richtung: Links + * + * @see #WEST + */ public static final Options.Direction LEFT = Options.Direction.LEFT; /** - * Schwarz + * Richtung: Oben links + * + * @see #NORTHWEST + */ + public static final Options.Direction UPLEFT = Options.Direction.UPLEFT; + + /** + * Richtung: Unten links + * + * @see #SOUTHWEST + */ + public static final Options.Direction DOWNLEFT = Options.Direction.DOWNLEFT; + + /** + * Richtung: Oben rechts + * + * @see #UPRIGHT + */ + public static final Options.Direction UPRIGHT = Options.Direction.UPRIGHT; + + /** + * Richtung: Unten rechts + * + * @see #SOUTHEAST + */ + public static final Options.Direction DOWNRIGHT = Options.Direction.DOWNRIGHT; + + + /** + * Farbe: Schwarz */ public static final Color BLACK = Color.BLACK; /** - * Weiß + * Farbe: Weiß */ public static final Color WHITE = Color.WHITE; /** - * Grau + * Farbe: Grau */ public static final Color GRAY = Color.GRAY; /** - * Dunkelgrau + * Farbe: Dunkelgrau */ public static final Color DARKGRAY = Color.DARKGRAY; /** - * Hellgrau + * Farbe: Hellgrau */ public static final Color LIGHTGRAY = Color.LIGHTGRAY; /** - * Rot + * Farbe: Rot */ public static final Color RED = Color.RED; /** - * Blau + * Farbe: Blau */ public static final Color BLUE = Color.BLUE; /** - * Grün + * Farbe: Grün */ public static final Color GREEN = Color.GREEN; /** - * Gelb + * Farbe: Gelb */ public static final Color YELLOW = Color.YELLOW; /** - * Orange + * Farbe: Orange */ public static final Color ORANGE = Color.ORANGE; /** - * Türkis + * Farbe: Türkis */ public static final Color CYAN = Color.CYAN; /** - * Magenta + * Farbe: Magenta */ public static final Color MAGENTA = Color.MAGENTA; /** - * Pink + * Farbe: Pink */ public static final Color PINK = Color.PINK; /** - * Lila + * Farbe: Lila */ public static final Color PURPLE = Color.PURPLE; /** - * Braun + * Farbe: Braun */ public static final Color BROWN = Color.BROWN; /** * Standardfarbe für den Hintergrund. */ - public static final Color STD_BACKGROUND = new Color(200, 200, 200); + public static Color DEFAULT_BACKGROUND = new Color(200, 200, 200); /** - * Konstante zur Prüfung, ob ein Mausknopf gedrückt wurde. + * Konstante zur Prüfung, ob kein Mausknopf gedrückt wurde. */ - public static final int NOBUTTON = MouseEvent.NOBUTTON; + public static final int NOMOUSE = MouseEvent.NOBUTTON; /** * Konstante zur Prüfung, ob Mausknopf 1 (links) gedrückt wurde. */ - public static final int BUTTON1 = MouseEvent.BUTTON1; + public static final int MOUSE1 = MouseEvent.BUTTON1; /** * Konstante zur Prüfung, ob Mausknopf 2 (rechts) gedrückt wurde. */ - public static final int BUTTON2 = MouseEvent.BUTTON2; + public static final int MOUSE2 = MouseEvent.BUTTON2; /** * Konstante zur Prüfung, ob Mausknopf 3 (mittig) gedrückt wurde. */ - public static final int BUTTON3 = MouseEvent.BUTTON3; + public static final int MOUSE3 = MouseEvent.BUTTON3; /** - * Konstante für die Kreiszahl Pi. + * Konstante für die Kreiszahl Pi (entspricht 180 Grad). */ public static final double PI = Math.PI; /** - * Konstante für die Hälfte der Kreiszahl Pi. + * Konstante für die Hälfte der Kreiszahl Pi (entspricht 90 Grad). */ public static final double HALF_PI = Math.PI / 2.0; /** - * Konstante für ein Viertel der Kreiszahl Pi. + * Konstante für ein Viertel der Kreiszahl Pi (entspricht 45 Grad). */ public static final double QUARTER_PI = Math.PI / 4.0; @@ -240,8 +367,7 @@ public class Constants { */ public static final double TWO_PI = Math.PI * 2.0; - - /** + /* * Globale Variablen, die von allen Klassen genutzt werden dürfen. Änderungen * wirken sich auf die aktuelle Zeichenmaschine aus und sollten nur von der * Zeichenmaschine selbst vorgenommen werden. @@ -268,70 +394,86 @@ public class Constants { public static double delta = 0.0; /** - * Die aktuelle {@code x}-Koordinate der Maus. + * Die aktuelle {@code x}-Koordinate der Maus. (Wird einmal pro Frame + * aktualisiert.) */ public static double mouseX = 0.0; /** - * Die aktuelle {@code y}-Koordinate der Maus. + * Die aktuelle {@code y}-Koordinate der Maus. (Wird einmal pro Frame + * aktualisiert.) */ public static double mouseY = 0.0; /** - * Die letzte {@code x}-Koordinate der Maus (wird einmal pro Frame + * Die letzte {@code x}-Koordinate der Maus. (Wird einmal pro Frame * aktualisiert). */ public static double pmouseX = 0.0; /** - * Die letzte {@code y}-Koordinate der Maus (wird einmal pro Frame - * aktualisiert). + * Die letzte {@code y}-Koordinate der Maus. (Wird einmal pro Frame + * aktualisiert.) */ public static double pmouseY = 0.0; /** - * Die aktuelle (current) {@code x}-Koordinate der Maus - * (wird bei jeder Mausbewegung aktualisiert). + * Die aktuelle (current) {@code x}-Koordinate der Maus. (Wird bei + * jeder Mausbewegung aktualisiert). */ public static double cmouseX = 0.0; /** - * Die aktuelle (current) {@code y}-Koordinate der Maus - * (wird bei jeder Mausbewegung aktualisiert). + * Die aktuelle (current) {@code y}-Koordinate der Maus. (Wird bei + * jeder Mausbewegung aktualisiert). */ public static double cmouseY = 0.0; /** - * Gibt an, ob ein Mausknopf derzeit gedrückt ist. + * Gibt an, ob derzeit ein Mausknopf gedrückt ist. */ public static boolean mousePressed = false; /** * Der aktuell gedrückte Mausknopf. Die Mausknöpfe werden durch die - * Konstanten {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2} und - * {@link #BUTTON3} angegeben. (Sie stimmen mit den Konstanten in - * {@link MouseEvent} überein. - * - * @see MouseEvent + * Konstanten {@link #NOMOUSE}, {@link #MOUSE1}, {@link #MOUSE2} und + * {@link #MOUSE3} angegeben. */ - public static int mouseButton = NOBUTTON; + public static int mouseButton = NOMOUSE; /** * Das zuletzt ausgelöste {@code MouseEvent}. */ public static MouseEvent mouseEvent; - // Mauszeiger + /** + * Mauszeiger: Pfeil + */ public static final int ARROW = Cursor.DEFAULT_CURSOR; + /** + * Mauszeiger: Fadenkreuz + */ public static final int CROSS = Cursor.CROSSHAIR_CURSOR; + /** + * Mauszeiger: Hand + */ public static final int HAND = Cursor.HAND_CURSOR; + /** + * Mauszeiger: Bewegungspfeile + */ public static final int MOVE = Cursor.MOVE_CURSOR; + /** + * Mauszeiger: Textzeiger + */ public static final int TEXT = Cursor.TEXT_CURSOR; + /** + * Mauszeiger: Ladezeiger + */ public static final int WAIT = Cursor.WAIT_CURSOR; /** @@ -340,14 +482,16 @@ public class Constants { public static boolean keyPressed = false; /** - * Das Zeichen der zuletzt gedrückten Taste. + * Das Text-Zeichen der zuletzt gedrückten Taste. Für Tasten ohne + * zugeordnetes Zeichen ist das Zeichen leer. */ public static char key = ' '; /** * Der Tastencode der zuletzt gedrückten Taste. Die Keycodes können in der - * Klasse {@link KeyEvent} nachgesehen werden. (Zum Beispiel - * {@link KeyEvent#VK_ENTER}.) + * Klasse {@link KeyEvent} nachgesehen werden. Die Keycodes für die + * wichtigsten Tasten sind als Konstanten mit dem Prefix {@code KEY_} + * vorhanden. (Zum Beispiel {@link #KEY_A}.) */ public static int keyCode = 0; @@ -359,12 +503,12 @@ public class Constants { /** * Die Höhe der Zeichenleinwand. */ - public static int width; + public static int canvasWidth; /** * Die Breite der Zeichenleinwand. */ - public static int height; + public static int canvasHeight; /** * Die Breite des Bildschirms, auf dem das Zeichenfenster geöffnet wurde. @@ -387,8 +531,11 @@ public class Constants { /** * Erstellt eine graue Farbe. Der Parameter {@code gray} gibt einen Grauwert - * zwischen 0 und 255 an, wobei - * 0 schwarz und 255 weiß ist. + * zwischen 0 und 255 an, wobei 0 schwarz und 255 weiß ist. + * + *


+	 * Color iron_grey = color(94);
+	 * 
* * @param gray Grauwert zwischen 0 und 255. * @return Ein passendes Farbobjekt. @@ -399,16 +546,16 @@ public class Constants { /** * Erstellt eine graue Farbe. Der Parameter {@code gray} gibt einen Grauwert - * zwischen 0 und 255 an, wobei - * 0 schwarz und 255 weiß ist. - * {@code alpha} gibt den den Transparentwert an (auch zwischen - * 0 und 255), wobei - * 0 komplett durchsichtig ist und 255 komplett - * deckend. + * zwischen 0 und 255 an, wobei 0 schwarz und 255 weiß ist. {@code alpha} + * gibt den Transparenzwert an (auch zwischen 0 und 255), wobei 0 komplett + * durchsichtig ist und 255 komplett deckend. + * + *

+	 * Color iron_grey_50 = color(94, 50);
+	 * 
* * @param gray Grauwert zwischen 0 und 255. - * @param alpha Transparentwert zwischen 0 und - * 255. + * @param alpha Transparenzwert zwischen 0 und 255. * @return Ein passendes Farbobjekt. */ public static final Color color( int gray, int alpha ) { @@ -420,6 +567,10 @@ public class Constants { * {@code blue} geben die Rot-, Grün- und Blauanteile der Farbe. Die Werte * liegen zwischen 0 und 255. * + *

+	 * Color arctic_blue = color(149, 214, 220);
+	 * 
+ * * @param red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. * @param blue Blauwert zwischen 0 und 255. @@ -432,17 +583,18 @@ public class Constants { /** * 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. + * liegen zwischen 0 und 255. {@code alpha} gibt den Transparenzwert an + * (auch zwischen 0 und 255), wobei 0 komplett durchsichtig ist und 255 + * komplett deckend. + * + *

+	 * Color arctic_blue_50 = color(149, 214, 220, 50);
+	 * 
* * @param red Rotwert zwischen 0 und 255. * @param green Grünwert zwischen 0 und 255. * @param blue Blauwert zwischen 0 und 255. - * @param alpha Transparenzwert zwischen 0 und - * 255. + * @param alpha Transparenzwert zwischen 0 und 255. * @return Ein passendes Farbobjekt. */ public static final Color color( int red, int green, int blue, int alpha ) { @@ -455,6 +607,10 @@ public class Constants { * Alle Farbkomponenten (Rot, Grün und Blau) werden zufällig im Bereich 0 * bis 255 gewählt. * + *

+	 * Color fillColor = randomColor();
+	 * 
+ * * @return Ein zufälliges Farbobjekt. */ public static final Color randomColor() { @@ -465,6 +621,10 @@ public class Constants { * Erzeugt eine "hübsche" zufällige Farbe. Die Farbe wird so gewählt, dass * die Farben nicht zu verwaschen oder dunkel wirken. * + *

+	 * Color fillColor = randomNiceColor();
+	 * 
+ * * @return Ein zufälliges Farbobjekt. */ public static final Color randomNiceColor() { @@ -480,6 +640,10 @@ public class Constants { * und die Sättigung (saturation) und Hellwert (brightness) im Bereich 0 bis * 100. * + *

+	 * Color arctic_blue = colorHsl(185, 32, 86);
+	 * 
+ * * @param h Farbton im Bereich 0 bis 360. * @param s Sättigung im Bereich 0 bis 100. * @param b Hellwert im Bereich 0 bis 100. @@ -498,6 +662,10 @@ public class Constants { * und die Sättigung (saturation) und Helligkeit (lightness) im Bereich 0 * bis 100. * + *

+	 * Color arctic_blue = colorHsl(185, 50, 72);
+	 * 
+ * * @param h Farbton im Bereich 0 bis 360. * @param s Sättigung im Bereich 0 bis 100. * @param l Helligkeit im Bereich 0 bis 100. @@ -509,14 +677,27 @@ public class Constants { return Color.getHSLColor(h % 360.0, s / 100.0, l / 100.0); } - public static final BufferedImage loadImage( String name ) { - return ImageLoader.loadImage(name); + // Ressourcen + + /** + * Lädt ein Bild aus einer Datei oder von einer Webadresse. + * + * @param source Ein Dateipfad oder eine Webadresse. + * @return Das geladene Bild. + * @see ImageLoader#loadImage(String) + */ + public static final BufferedImage loadImage( String source ) { + return ImageLoader.loadImage(source); } // Mathematische Funktionen /** - * Berechnet das Minimum aller übergebenen Werte. + * Berechnet das Minimum aller angegebenen Werte. + * + *

+	 * double minimum = min(1.0, 5.1, 3.2); // 1.0
+	 * 
* * @param numbers Die Werte, aus denen das Minimum ermittelt werden soll. * @return Das Minimum der Werte. @@ -536,7 +717,11 @@ public class Constants { } /** - * Berechnet das Maximum aller übergebenen Werte. + * Berechnet das Maximum aller angegebenen Werte. + * + *

+	 * double maximum = max(1.0, 5.1, 3.2); // 5.1
+	 * 
* * @param numbers Die Werte, aus denen das Maximum ermittelt werden soll. * @return Das Maximum der Werte. @@ -555,18 +740,39 @@ public class Constants { return max; } + /** + * Berechnet die Summe alle angegebenen Werte. + * + *

+	 * double summe = sum(1.0, 2.0, 3.2); // 6.2
+	 * 
+ * + * @param numbers Die Werte, aus denen die Summe berechnet werden soll. + * @return Die Summe der Werte. + */ public static final double sum( double... numbers ) { if( numbers == null ) { throw new IllegalArgumentException("Array may not be or empty."); } double sum = 0; - for( int i = 0; i < numbers.length; i++ ) { - sum += numbers[i]; + for( double number : numbers ) { + sum += number; } return sum; } + /** + * Berechnet das arithmetische Mittel der angegebenen Werte. + * + *

+	 * double summe = sum(1.0, 2.2, 3.1); // 2.1
+	 * 
+ * + * @param numbers Die Werte, aus denen der MIttelwert berechnet werden + * soll. + * @return Der Mittelwert der Werte. + */ public static final double avg( double... numbers ) { if( numbers == null || numbers.length == 0 ) { throw new IllegalArgumentException("Array may not be or empty."); @@ -576,7 +782,11 @@ public class Constants { } /** - * Ermittelt den Absolutbetrag der Zahl {@code x}. + * Ermittelt den Absolutbetrag der angegebenen Zahl. + * + *

+	 * double positiv = abs(-3.2); // 3.2
+	 * 
* * @param x Eine Zahl. * @return Der Absolutbetrag. @@ -586,7 +796,11 @@ public class Constants { } /** - * Ermittelt das Vorzeichen der Zahl {@code x}. + * Ermittelt das Vorzeichen der angegebenen Zahl. + * + *

+	 * double vorzeichen = sign(-3.2); // -1.0
+	 * 
* * @param x Eine Zahl. * @return -1, 1 oder 0. @@ -596,7 +810,11 @@ public class Constants { } /** - * Rundet die Zahl {@code x}. + * Rundet die angegebene Zahl auf die nächste ganze Zahl. + * + *

+	 * double gerundet = sign(3.2); // 3.0
+	 * 
* * @param x Eine Zahl. * @return Die gerundete Zahl. @@ -606,7 +824,11 @@ public class Constants { } /** - * Rundet die Zahl {@code x} ab. + * Rundet die angegebene Zahl ab. + * + *

+	 * double abgerundet = sign(3.2); // 3.0
+	 * 
* * @param x Eine Zahl. * @return Die abgerundete Zahl. @@ -616,7 +838,11 @@ public class Constants { } /** - * Rundet die Zahl {@code x} auf. + * Rundet die angegebene Zahl auf. + * + *

+	 * double aufgerundet = sign(3.2); // 4.0
+	 * 
* * @param x Eine Zahl. * @return Die aufgerundete Zahl. @@ -626,7 +852,11 @@ public class Constants { } /** - * Ermittelt die Quadratwurzel der Zahl {@code x}. + * Ermittelt die Quadratwurzel der angegebenen Zahl. + * + *

+	 * double wurzel = sqrt(16); // 4.0
+	 * 
* * @param x Eine Zahl. * @return Die Quadratwurzel. @@ -636,19 +866,27 @@ public class Constants { } /** - * Ermittelt die Potenz der Zahl {@code x} zum Exponenten {@code p}. + * Ermittelt die Potenz der angegebenen Zahl zum angegebenen Exponenten. + * + *

+	 * double hoch4 = sqrt(8, 4); // 4096.0
+	 * 
* * @param x Eine Zahl. - * @param p Der Exponent. - * @return {@code x} hoch {@code p}. + * @param e Der Exponent. + * @return {@code x} hoch {@code e}. */ - public static final double pow( double x, double p ) { - return Math.pow(x, p); + public static final double pow( double x, double e ) { + return Math.pow(x, e); } /** * Rechnet von Grad in Radian um. * + *

+	 * double radian = radians(360); // 6.28318530717959
+	 * 
+ * * @param angle Ein Winkel in Grad. * @return Der Winkel in Radian. */ @@ -657,7 +895,11 @@ public class Constants { } /** - * Rechent von Radian in Grad um. + * Rechnet von Radian in Grad um. + * + *

+	 * double grad = radians(HALF_PI); // 90.0
+	 * 
* * @param radians Der Winkel in Radian. * @return Der Winkel in Grad. @@ -667,7 +909,11 @@ public class Constants { } /** - * Ermittelt den Sinus der Zahl {@code x}. + * Ermittelt den Sinus der angegebenen Zahl. + * + *

+	 * double sinus = sin(0.0); // 0.0
+	 * 
* * @param x Eine Zahl. * @return {@code sin(x)}. @@ -677,7 +923,11 @@ public class Constants { } /** - * Ermittelt den Kosinus der Zahl {@code x}. + * Ermittelt den Kosinus der angegebenen Zahl. + * + *

+	 * double kosinus = cos(0.0); // 1.0
+	 * 
* * @param x Eine Zahl. * @return {@code cos(x)}. @@ -687,7 +937,11 @@ public class Constants { } /** - * Ermittelt den Tangens der Zahl {@code x}. + * Ermittelt den Tangens der angegebenen Zahl. + * + *

+	 * double sinus = tan(1.0); // 1.5574077246549
+	 * 
* * @param x Eine Zahl. * @return {@code tan(x)}. @@ -697,7 +951,7 @@ public class Constants { } /** - * Ermittelt den Arkussinus der Zahl {@code x}. + * Ermittelt den Arkussinus der angegebenen Zahl. * * @param x Eine Zahl. * @return {@code asin(x)}. @@ -707,7 +961,7 @@ public class Constants { } /** - * Ermittelt den Arkuskosinus der Zahl {@code x}. + * Ermittelt den Arkuskosinus der angegebenen Zahl. * * @param x Eine Zahl. * @return {@code acos(x)}. @@ -717,7 +971,7 @@ public class Constants { } /** - * Ermittelt den Arkusktangens der Zahl {@code x}. + * Ermittelt den Arkusktangens der angegebenen Zahl. * * @param x Eine Zahl. * @return {@code atan(x)}. @@ -727,11 +981,17 @@ public class Constants { } /** - * Beschränkt die Zahl {@code x} auf das Intervall {@code [min, max]}. + * Beschränkt die angegebene Zahl auf das Intervall {@code [min, max]}. * Liegt {@code x} außerhalb des Intervalls, wird eine der Grenzen * zurückgegeben. * + *

+	 * double beschraenkt1 = limit(2.1, 0.0, 3.0); // 2.1
+	 * double beschraenkt2 = limit(4.1, 0.0, 3.0); // 1.0
+	 * 
+ * * @param x Eine Zahl. + * @param min Das Minimum des Intervalls. * @param max Das Maximum des Intervalls. * @return Eine Zahl im Intervall {@code [min, max]}. */ @@ -746,22 +1006,28 @@ public class Constants { } /** - * Beschränkt die Zahl {@code x} auf das Intervall {@code [min, max]}. - * Liegt {@code x} außerhalb des Intervalls, wird eine der Grenzen + * Beschränkt die angegebene Zahl auf das Intervall {@code [min, max]}. + * Liegt {@code i} außerhalb des Intervalls, wird eine der Grenzen * zurückgegeben. * - * @param x Eine Zahl. + *

+	 * double beschraenkt1 = limit(2, 0, 3); // 2
+	 * double beschraenkt2 = limit(4, 0, 3); // 3
+	 * 
+ * + * @param i Eine Zahl. + * @param min Das Minimum des Intervalls. * @param max Das Maximum des Intervalls. * @return Eine Zahl im Intervall {@code [min, max]}. */ - public static final int limit( int x, int min, int max ) { - if( x > max ) { + public static final int limit( int i, int min, int max ) { + if( i > max ) { return max; } - if( x < min ) { + if( i < min ) { return min; } - return x; + return i; } /** @@ -771,30 +1037,91 @@ public class Constants { *
 	 * from - t * (from + to)
 	 * 
+ *

+ * In der Regel liegt {@code t} im Intervall {@code [0, 1]}. Für + * {@code t = 0} ist das Ergebnis {@code from} und für {@code t = 1} ist das + * Ergebnis {@code to}. {@code t} kann aber auch Werte außerhalb des + * Intervalls annehmen. Für {@code t = 2} ist das Ergebnis beispielsweise + * {@code 2*to}; + * + *


+	 * double interpoliert = interpolate(100.0, 500.0, 0.5); // 300.0
+	 * double interpoliert = interpolate(100.0, 500.0, 1.0); // 500.0
+	 * double interpoliert = interpolate(100.0, 500.0, 1.5); // 750.0
+	 * 
* * @param from Startwert * @param to Zielwert - * @param t Wert zwischen 0 und 1. + * @param t Anteil des Ergebnisses auf der Strecke zwischen {@code from} + * und {@code to}. * @return Das Ergebnis der linearen Interpolation. */ public static final double interpolate( double from, double to, double t ) { return from + t * (to - from); } + /** + * Interpoliert einen Wert zwischen {@code from} und {@code to}, aber + * beschränkt {@code t} auf das Intervall {@code [0, 1]}. + * + *

+	 * double interpoliert = interpolate(100.0, 500.0, 0.5); // 300.0
+	 * double interpoliert = interpolate(100.0, 500.0, 1.0); // 500.0
+	 * double interpoliert = interpolate(100.0, 500.0, 1.5); // 500.0
+	 * 
+ * + * @param from Startwert + * @param to Zielwert + * @param t Wert zwischen 0 und 1. + * @return + * @see #interpolate(double, double, double) + */ public static final double morph( double from, double to, double t ) { return interpolate(from, to, limit(t, 0.0, 1.0)); } + /** + * Bestimmt für den angegebenen Wert aus dem Intervall + * {@code [fromMin, fromMax]} einen zugehörigen Wert aus dem Intervall + * {@code [toMin, toMax]}. + *

+ * Für {@code value = fromMin} wird {@code toMin} zurückgegeben. Für + * {@code value = fromMax} ist das Ergebnis {@code toMax}. Befindet sich + * {@code value} genau mittig zwischen {@code fromMin} und {@code fromMax}, + * dann ist das Ergebnis genau {@code interpolate(toMin, toMax, 0.5)}. + *

+ * Mit {@code map()} lassen sich Werte eines Originalintervalls auf ein + * Zielintervalls transponieren. Dies ist beispielsweise hilfreich, um aus + * der Mausbewegung die relative Position auf der Zeichenfläche zu + * bestimmen: + * + *


+	 * double relativeMouseX = map(mouseX, 0.0, canvasWidth, 0.0, 1.0);
+	 * 
+ * + * @param value Der Wert aus dem original Intervall. + * @param fromMin Untere Grenze des original Intervalls. + * @param fromMax Obere Grenze des original Intervalls. + * @param toMin Untere Grenze des Zielintervalls. + * @param toMax Obere Grenze des Zielintervalls. + * @return Der zugehörige Wert aus dem Zielintervall. + * @see #interpolate(double, double, double) + */ public static final double map( double value, double fromMin, double fromMax, double toMin, double toMax ) { return interpolate(toMin, toMax, (value - fromMin) / (fromMax - fromMin)); } /** - * Shared Random instance + * Geteilte {@code Random}-Instanz für einheitliche Zufallszahlen. */ private static Random random = null; - private static final Random getRandom() { + /** + * Gibt die geteilte {@code Random}-Instanz zurück. + * + * @return Die {@code Random}-Instanz. + */ + private static Random getRandom() { if( random == null ) { random = new Random(); } @@ -885,8 +1212,7 @@ public class Constants { * Erzeugt einen zufälligen Wahrheitswert. {@code true} wird mit der * Wahrscheinlichkeit {@code percent} Prozent erzeugt. * - * @param percent Eine Prozentzahl zwischen 0 und - * 100. + * @param percent Eine Prozentzahl zwischen 0 und 100. * @return Ein Wahrheitswert. */ public static final boolean randomBool( int percent ) { @@ -897,6 +1223,7 @@ public class Constants { * Erzeugt einen zufälligen Wahrheitswert. {@code true} wird mit der * Wahrscheinlichkeit {@code weight} erzeugt. * + * @param weight Wahrscheinlichkeit für {@code true}. * @return Ein Wahrheitswert. */ public static final boolean randomBool( double weight ) { @@ -917,6 +1244,7 @@ public class Constants { * Wählt ein zufälliges Element aus dem Array aus. * * @param values Ein Array mit Werten, die zur Auswahl stehen. + * @param Datentyp des Elements. * @return Ein zufälliges Element aus dem Array. */ public static final T choice( T[] values ) { @@ -924,9 +1252,11 @@ public class Constants { } /** - * Wählt ein zufälliges Element aus dem Array aus. + * Wählt die angegebene Anzahl Elemente aus dem Array aus. * * @param values Ein Array mit Werten, die zur Auswahl stehen. + * @param n Anzahl der auszuwählenden Elemente. + * @param Datentyp der Elemente. * @return Ein zufälliges Element aus dem Array. */ public static final T[] choice( T[] values, int n ) { @@ -937,50 +1267,159 @@ public class Constants { return (T[]) result; } + /** + * Geteilte {@code Noise}-Instanz zur Erzeugung von Perlin-Noise. + */ + private static Noise noise = null; + + /** + * Zähler für den letzten generierten Noise-Wert. + */ + private static int N = 0; + + /** + * Gibt die geteilte {@code Random}-Instanz zurück. + * + * @return Die {@code Random}-Instanz. + */ + private static Noise getNoise() { + if( noise == null ) { + noise = new Noise(getRandom()); + } + return noise; + } + /** * Erzeugt den nächsten Wert eines Perlin-Noise. * - * @return + * @return Ein zufälliger Wert. */ public static final double noise() { - // TODO: Implementieren - return 0.0; + return getNoise().noise(N++); + } + + /** + * Erzeugt den nächsten Wert eines Perlin-Noise. + * + * @return Ein zufälliger Wert. + */ + public static final double noise( double x ) { + return getNoise().noise(x); + } + + /** + * Erzeugt den nächsten Wert eines zweidimensionalen Perlin-Noise. + * + * @return Ein zufälliger Wert. + */ + public static final double noise( double x, double y ) { + return getNoise().noise(x, y); + } + + /** + * Erzeugt den nächsten Wert eines dreidimensionalen Perlin-Noise. + * + * @return Ein zufälliger Wert. + */ + public static final double noise( double x, double y, double z ) { + return getNoise().noise(x, y, z); } // Typecasting - public static final int getInt( char value ) { + + /** + * Konvertiert das angegebenen Zeichen in eine ganze Zahl. Das Zeichen wird + * jeweils in seinen ASCII-Codepoint transformiert. + * + * @param value Der Wert. + * @return Eine ganze Zahl. + */ + public static final int asInt( char value ) { + return value; + } + + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. + * + * @param value Der Wert. + * @return Der Wert. + */ + public static final int asInt( byte value ) { + return value; + } + + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. + * + * @param value Der Wert. + * @return Der Wert. + */ + public static final int asInt( short value ) { + return value; + } + + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. Zahlen größer als + * {@link Integer#MAX_VALUE} werden auf {@code MAX_VALUE} reduziert. + * Entsprechendes gilt für Werte kleiner {@link Integer#MIN_VALUE}. + * + * @param value Der Wert. + * @return Eine ganze Zahl. + */ + public static final int asInt( long value ) { return (int) value; } - public static final int getInt( byte value ) { + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. + * + * @param value Der Wert. + * @return Der abgerundete Wert. + */ + public static final int asInt( double value ) { return (int) value; } - public static final int getInt( short value ) { + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. + * + * @param value Der Wert. + * @return Der abgerundete Wert. + */ + public static final int asInt( float value ) { return (int) value; } - public static final int getInt( long value ) { - return (int) value; + /** + * Konvertiert den angegebenen Wert in eine ganze Zahl. + * + * @param value Der Wert. + * @return Der Wert. + */ + public static final int asInt( int value ) { + return value; } - public static final int getInt( double value ) { - return (int) value; + /** + * Konvertiert den angegebenen Wahrheitswert in eine ganze Zahl. + * {@code true} entspricht 1, {@code false} wird zu 0. + * + * @param value Der Wert. + * @return 1 oder 0. + */ + public static final int asInt( boolean value ) { + return value ? 1 : 0; } - public static final int getInt( float value ) { - return (int) value; - } - - public static final int getInt( int value ) { - return (int) value; - } - - public static final int getInt( boolean value ) { - return value ? 0 : 1; - } - - public static final int getInt( String value ) { + /** + * Konvertiert den angegebenen Text in eine ganze Zahl. Kann der Text nicht + * umgewandelt werden, dann wird 0 zurückgegeben. + * + * @param value Der Wert. + * @return Eine ganze Zahl- + * @see Integer#parseInt(String) + */ + public static final int asInt( String value ) { try { return Integer.parseInt(value); } catch( NumberFormatException ex ) { @@ -988,39 +1427,39 @@ public class Constants { } } - public static final double getDouble( char value ) { + public static final double asDouble( char value ) { return (double) value; } - public static final double getDouble( byte value ) { - return (double) value; - } - - public static final double getDouble( short value ) { - return (double) value; - } - - public static final double getDouble( long value ) { - return (double) value; - } - - public static final double getDouble( double value ) { + public static final double asDouble( byte value ) { return value; } - public static final double getDouble( float value ) { + public static final double asDouble( short value ) { + return value; + } + + public static final double asDouble( long value ) { return (double) value; } - public static final double getDouble( int value ) { - return (double) value; + public static final double asDouble( double value ) { + return value; } - public static final double getDouble( boolean value ) { - return value ? 0.0 : 1.0; + public static final double asDouble( float value ) { + return value; } - public static final double getDouble( String value ) { + public static final double asDouble( int value ) { + return value; + } + + public static final double asDouble( boolean value ) { + return value ? 1.0 : 0.0; + } + + public static final double asDouble( String value ) { try { return Double.parseDouble(value); } catch( NumberFormatException ex ) { @@ -1028,43 +1467,99 @@ public class Constants { } } - public static final boolean getBool( char value ) { + public static final boolean asBool( char value ) { return value != 0; } - public static final boolean getBool( byte value ) { + public static final boolean asBool( byte value ) { return value != 0; } - public static final boolean getBool( short value ) { + public static final boolean asBool( short value ) { return value != 0; } - public static final boolean getBool( int value ) { + public static final boolean asBool( int value ) { return value != 0; } - public static final boolean getBool( long value ) { + public static final boolean asBool( long value ) { return value != 0L; } - public static final boolean getBool( double value ) { + public static final boolean asBool( double value ) { return value != 0.0; } - public static final boolean getBool( float value ) { + public static final boolean asBool( float value ) { return value != 0.0f; } - public static final boolean getBool( boolean value ) { + public static final boolean asBool( boolean value ) { return value; } - public static final boolean getBool( String value ) { + public static final boolean asBool( String value ) { return Boolean.parseBoolean(value); } - // Konstants for Key events (Copied from KeyEvent) + /** + * Formt die angegebene Zahl in ihre Binärdarstellung um. + * + *

+	 * int bin = binary(10); // "1010"
+	 * 
+ * + * @param i Eine Zahl. + * @return Die binäre Darstellung der Zahl als Text. + */ + public static final String binary( int i ) { + return Integer.toBinaryString(i); + } + + /** + * Formt die angegebene Binärzahl in eine Dezimalzahl um. + * + *

+	 * int dezimal = romBinary("1010"); // 10
+	 * 
+ * + * @param binary Ein Text nur aus "0" und "1". + * @return Der Wert der Binärzahl. + */ + public static final int fromBinary( String binary ) { + return Integer.valueOf(binary, 2); + } + + /** + * Formt die angegebene Zahl in ihre hexadezimal Darstellung um. + * + *

+	 * int hexa = hex(255); // "FF"
+	 * 
+ * + * @param i Eine Zahl. + * @return Die hexadezimal Darstellung der Zahl als Text. + */ + public static final String hex( int i ) { + return Integer.toHexString(i); + } + + /** + * Formt die angegebene Binärzahl in eine Dezimalzahl um. + * + *

+	 * int dezimal = romHex("FF"); // 255
+	 * 
+ * + * @param binary Ein Text nur aus den Zeichen "0" bis "9" und "A" bis "F". + * @return Der Wert der Binärzahl. + */ + public static final int fromHex( String binary ) { + return Integer.valueOf(binary, 16); + } + + // Konstants für Key events (Copied from KeyEvent) /** * Constant for the ENTER virtual key. @@ -1248,7 +1743,7 @@ public class Constants { */ public static final int KEY_EQUALS = KeyEvent.VK_EQUALS; - /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ + /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ /** * Constant for the "A" key. diff --git a/src/main/java/schule/ngb/zm/Options.java b/src/main/java/schule/ngb/zm/Options.java index 70cf071..0997336 100644 --- a/src/main/java/schule/ngb/zm/Options.java +++ b/src/main/java/schule/ngb/zm/Options.java @@ -56,7 +56,12 @@ public final class Options { UP(NORTH), DOWN(SOUTH), LEFT(WEST), - RIGHT(EAST); + RIGHT(EAST), + + UPLEFT(NORTHWEST), + DOWNLEFT(SOUTHWEST), + UPRIGHT(NORTHEAST), + DOWNRIGHT(SOUTHEAST); public final byte x, y; diff --git a/src/main/java/schule/ngb/zm/Zeichenleinwand.java b/src/main/java/schule/ngb/zm/Zeichenleinwand.java index 232b688..d59fdaf 100644 --- a/src/main/java/schule/ngb/zm/Zeichenleinwand.java +++ b/src/main/java/schule/ngb/zm/Zeichenleinwand.java @@ -1,7 +1,5 @@ package schule.ngb.zm; -import schule.ngb.zm.shapes.ShapesLayer; - import java.awt.Canvas; import java.awt.Graphics; import java.awt.Graphics2D; @@ -37,12 +35,12 @@ public class Zeichenleinwand extends Canvas { super.setSize(width, height); this.setPreferredSize(this.getSize()); this.setMinimumSize(this.getSize()); - this.setBackground(Constants.STD_BACKGROUND.getJavaColor()); + this.setBackground(Constants.DEFAULT_BACKGROUND.getJavaColor()); // Liste der Ebenen initialisieren und die Standardebenen einfügen layers = new LinkedList<>(); synchronized( layers ) { - layers.add(new ColorLayer(width, height, Constants.STD_BACKGROUND)); + layers.add(new ColorLayer(width, height, Constants.DEFAULT_BACKGROUND)); } } diff --git a/src/main/java/schule/ngb/zm/Zeichenmaschine.java b/src/main/java/schule/ngb/zm/Zeichenmaschine.java index f5849cb..e7581da 100644 --- a/src/main/java/schule/ngb/zm/Zeichenmaschine.java +++ b/src/main/java/schule/ngb/zm/Zeichenmaschine.java @@ -277,8 +277,8 @@ public class Zeichenmaschine extends Constants { } // Wir kennen nun den Bildschirm und können die Breite / Höhe abrufen. - this.width = width; - this.height = height; + this.canvasWidth = width; + this.canvasHeight = height; java.awt.Rectangle displayBounds = displayDevice.getDefaultConfiguration().getBounds(); this.screenWidth = (int) displayBounds.getWidth(); this.screenHeight = (int) displayBounds.getHeight(); @@ -408,8 +408,8 @@ public class Zeichenmaschine extends Constants { frame.setResizable(false); // Should be set anyway displayDevice.setFullScreenWindow(frame); // Update width / height - initialWidth = width; - initialHeight = height; + initialWidth = canvasWidth; + initialHeight = canvasHeight; changeSize(screenWidth, screenHeight); // Register ESC as exit fullscreen canvas.addKeyListener(fullscreenExitListener); @@ -595,11 +595,11 @@ public class Zeichenmaschine extends Constants { * @see #setFullscreen(boolean) */ private void changeSize( int newWidth, int newHeight ) { - width = Math.min(Math.max(newWidth, 100), screenWidth); - height = Math.min(Math.max(newHeight, 100), screenHeight); + canvasWidth = Math.min(Math.max(newWidth, 100), screenWidth); + canvasHeight = Math.min(Math.max(newHeight, 100), screenHeight); if( canvas != null ) { - canvas.setSize(width, height); + canvas.setSize(canvasWidth, canvasHeight); } } @@ -629,7 +629,7 @@ public class Zeichenmaschine extends Constants { * @return Die Breite der {@link Zeichenleinwand}. */ public final int getWidth() { - return width; + return canvasWidth; } /** @@ -638,7 +638,7 @@ public class Zeichenmaschine extends Constants { * @return Die Höhe der {@link Zeichenleinwand}. */ public final int getHeight() { - return height; + return canvasHeight; } /** @@ -718,7 +718,7 @@ public class Zeichenmaschine extends Constants { public final ColorLayer getBackgroundLayer() { ColorLayer layer = canvas.getLayer(ColorLayer.class); if( layer == null ) { - layer = new ColorLayer(STD_BACKGROUND); + layer = new ColorLayer(DEFAULT_BACKGROUND); canvas.addLayer(0, layer); } return layer; @@ -812,7 +812,7 @@ public class Zeichenmaschine extends Constants { BufferedImage img = ImageLoader.createImage(canvas.getWidth(), canvas.getHeight()); Graphics2D g = img.createGraphics(); - g.setColor(STD_BACKGROUND.getJavaColor()); + g.setColor(DEFAULT_BACKGROUND.getJavaColor()); g.fillRect(0, 0, img.getWidth(), img.getHeight()); canvas.draw(g); g.dispose(); @@ -836,7 +836,7 @@ public class Zeichenmaschine extends Constants { BufferedImage img = ImageLoader.createImage(canvas.getWidth(), canvas.getHeight()); Graphics2D g = img.createGraphics(); - g.setColor(STD_BACKGROUND.getJavaColor()); + g.setColor(DEFAULT_BACKGROUND.getJavaColor()); g.fillRect(0, 0, img.getWidth(), img.getHeight()); canvas.draw(g); g.dispose(); @@ -1166,7 +1166,7 @@ public class Zeichenmaschine extends Constants { break; case MouseEvent.MOUSE_RELEASED: mousePressed = false; - mouseButton = NOBUTTON; + mouseButton = NOMOUSE; mousePressed(evt); break; case MouseEvent.MOUSE_DRAGGED: diff --git a/src/main/java/schule/ngb/zm/shapes/Shape.java b/src/main/java/schule/ngb/zm/shapes/Shape.java index 6e3866b..630f5cf 100644 --- a/src/main/java/schule/ngb/zm/shapes/Shape.java +++ b/src/main/java/schule/ngb/zm/shapes/Shape.java @@ -243,7 +243,7 @@ public abstract class Shape extends FilledShape { } public void alignTo( Options.Direction dir, double buff ) { - Point2D anchorShape = Shape.getAnchorPoint(width, height, dir); + Point2D anchorShape = Shape.getAnchorPoint(canvasWidth, canvasHeight, dir); Point2D anchorThis = this.getAbsAnchorPoint(dir); this.x += Math.abs(dir.x) * (anchorShape.getX() - anchorThis.getX()) + dir.x * buff; diff --git a/src/main/java/schule/ngb/zm/util/Noise.java b/src/main/java/schule/ngb/zm/util/Noise.java new file mode 100644 index 0000000..a20168f --- /dev/null +++ b/src/main/java/schule/ngb/zm/util/Noise.java @@ -0,0 +1,308 @@ +package schule.ngb.zm.util; + +import java.util.Random; + +/** + * Zufallsgenerator für Perlin-Noise. + *

+ * Die Implementierung basiert auf dem von Ken perlin entwickelten Algorithmus + * und wurde von Matthew A. Johnston für Java implementiert. + *

+ * Original KOmmentar: + *

+ * This is Ken Perlin's implementation of Perlin Noise but modified to be more
+ * OOP.
+ * 
+ * + * @author Ken Perlin, Matthew A. Johnston (WarmWaffles) + */ +public class Noise { + + private Random rand; + + private static final int P = 8; + + private static final int B = 1 << P; + + private static final int M = B - 1; + + private static final int NP = 8; + + private static final int N = 1 << NP; + + private int[] p; + + private double[][] g2; + + private double[] g1; + + private static double[][] points; + + + public Noise() { + this(System.nanoTime()); + } + + public Noise( long seed ) { + this(new Random(seed)); + } + + public Noise( Random rand ) { + p = new int[B + B + 2]; + g2 = new double[B + B + 2][2]; + g1 = new double[B + B + 2]; + + points = new double[32][3]; + + this.rand = rand; + init(); + } + + /** + * A stub function that calls {@link #init()} + * + * @param seed + */ + public void setSeed( int seed ) { + this.rand = new Random(seed); + init(); + } + + public void setRandom( Random rand ) { + this.rand = rand; + init(); + } + + public double noise( double x, double y, double z ) { + int bx, by, bz, b0, b1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, rz, sx, sy, sz, a, b, c, d, u, v, q[]; + + bx = (int) Math.IEEEremainder(Math.floor(x), B); + if( bx < 0 ) + bx += B; + + rx0 = x - Math.floor(x); + rx1 = rx0 - 1; + + by = (int) Math.IEEEremainder(Math.floor(y), B); + if( by < 0 ) + by += B; + + ry0 = y - Math.floor(y); + ry1 = ry0 - 1; + + bz = (int) Math.IEEEremainder(Math.floor(z), B); + if( bz < 0 ) + bz += B; + + rz = z - Math.floor(z); + + /* + if (bx < 0 || bx >= B + B + 2) + System.out.println(bx); + */ + b0 = p[bx]; + + bx++; + + b1 = p[bx]; + + b00 = p[b0 + by]; + b10 = p[b1 + by]; + + by++; + + b01 = p[b0 + by]; + b11 = p[b1 + by]; + + sx = s_curve(rx0); + sy = s_curve(ry0); + sz = s_curve(rz); + + q = G(b00 + bz); + u = rx0 * q[0] + ry0 * q[1] + rz * q[2]; + q = G(b10 + bz); + v = rx1 * q[0] + ry0 * q[1] + rz * q[2]; + a = lerp(sx, u, v); + q = G(b01 + bz); + u = rx0 * q[0] + ry1 * q[1] + rz * q[2]; + q = G(b11 + bz); + v = rx1 * q[0] + ry1 * q[1] + rz * q[2]; + b = lerp(sx, u, v); + c = lerp(sy, a, b); + + bz++; + rz--; + + q = G(b00 + bz); + u = rx0 * q[0] + ry0 * q[1] + rz * q[2]; + q = G(b10 + bz); + v = rx1 * q[0] + ry0 * q[1] + rz * q[2]; + a = lerp(sx, u, v); + q = G(b01 + bz); + u = rx0 * q[0] + ry1 * q[1] + rz * q[2]; + q = G(b11 + bz); + v = rx1 * q[0] + ry1 * q[1] + rz * q[2]; + b = lerp(sx, u, v); + d = lerp(sy, a, b); + + return lerp(sz, c, d); + } + + public double noise( double x, double y ) { + int bx0, bx1, by0, by1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v, q[]; + int i, j; + + t = x + N; + bx0 = ((int) t) & M; + bx1 = (bx0 + 1) & M; + rx0 = t - (int) t; + rx1 = rx0 - 1; + + t = y + N; + by0 = ((int) t) & M; + by1 = (by0 + 1) & M; + ry0 = t - (int) t; + ry1 = ry0 - 1; + + i = p[bx0]; + j = p[bx1]; + + b00 = p[i + by0]; + b10 = p[j + by0]; + b01 = p[i + by1]; + b11 = p[j + by1]; + + sx = s_curve(rx0); + sy = s_curve(ry0); + + q = g2[b00]; + u = rx0 * q[0] + ry0 * q[1]; + q = g2[b10]; + v = rx1 * q[0] + ry0 * q[1]; + a = lerp(sx, u, v); + + q = g2[b01]; + u = rx0 * q[0] + ry1 * q[1]; + q = g2[b11]; + v = rx1 * q[0] + ry1 * q[1]; + b = lerp(sx, u, v); + + return lerp(sy, a, b); + } + + public double noise( double x ) { + + int bx0, bx1; + double rx0, rx1, sx, t, u, v; + t = x + N; + bx0 = ((int) t) & M; + bx1 = (bx0 + 1) & M; + rx0 = t - (int) t; + rx1 = rx0 - 1; + + sx = s_curve(rx0); + u = rx0 * g1[p[bx0]]; + v = rx1 * g1[p[bx1]]; + + return lerp(sx, u, v); + } + + // ======================================================================== + // PRIVATE + // ======================================================================== + private void normalize2( double v[] ) { + double s; + s = Math.sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] = v[0] / s; + v[1] = v[1] / s; + } + + private double[] G( int i ) { + return points[i % 32]; + } + + private double s_curve( double t ) { + return t * t * (3 - t - t); + } + + private double lerp( double t, double a, double b ) { + return a + t * (b - a); + } + + private final void init() { + int i, j, k; + double u, v, w, U, V, W, Hi, Lo; + + for( i = 0; i < B; i++ ) { + p[i] = i; + g1[i] = 2 * rand.nextDouble() - 1; + + do { + u = 2 * rand.nextDouble() - 1; + v = 2 * rand.nextDouble() - 1; + } while( u * u + v * v > 1 || + Math.abs(u) > 2.5 * Math.abs(v) || + Math.abs(v) > 2.5 * Math.abs(u) || + Math.abs(Math.abs(u) - Math.abs(v)) < .4 ); + + g2[i][0] = u; + g2[i][1] = v; + + normalize2(g2[i]); + + do { + u = 2 * rand.nextDouble() - 1; + v = 2 * rand.nextDouble() - 1; + w = 2 * rand.nextDouble() - 1; + U = Math.abs(u); + V = Math.abs(v); + W = Math.abs(w); + Lo = Math.min(U, Math.min(V, W)); + Hi = Math.max(U, Math.max(V, W)); + } while( u * u + v * v + w * w > 1 + || Hi > 4 * Lo + || Math.min(Math.abs(U - V), + Math.min(Math.abs(U - W), Math.abs(V - W))) < .2 ); + } + + while( --i > 0 ) { + k = p[i]; + j = (int) (rand.nextLong() & M); + p[i] = p[j]; + p[j] = k; + } + for( i = 0; i < B + 2; i++ ) { + p[B + i] = p[i]; + g1[B + i] = g1[i]; + for( j = 0; j < 2; j++ ) + g2[B + i][j] = g2[i][j]; + } + + points[3][0] = points[3][1] = points[3][2] = Math.sqrt(1. / 3); + double r2 = Math.sqrt(1. / 2); + double s = Math.sqrt(2 + r2 + r2); + + for( i = 0; i < 3; i++ ) + for( j = 0; j < 3; j++ ) + points[i][j] = (i == j ? 1 + r2 + r2 : r2) / s; + + + for( i = 0; i <= 1; i++ ) { + for( j = 0; j <= 1; j++ ) { + for( k = 0; k <= 1; k++ ) { + int n = i + j * 2 + k * 4; + if( n > 0 ) { + for( int m = 0; m < 4; m++ ) { + points[4 * n + m][0] = (i == 0 ? 1 : -1) * points[m][0]; + points[4 * n + m][1] = (j == 0 ? 1 : -1) * points[m][1]; + points[4 * n + m][2] = (k == 0 ? 1 : -1) * points[m][2]; + } + } + } + } + } + } + +} diff --git a/src/main/java/schule/ngb/zm/util/Validator.java b/src/main/java/schule/ngb/zm/util/Validator.java index 50067b9..cb28143 100644 --- a/src/main/java/schule/ngb/zm/util/Validator.java +++ b/src/main/java/schule/ngb/zm/util/Validator.java @@ -136,8 +136,27 @@ public class Validator { } */ + + public static final T[] requireNotEmpty( T[] arr ) { + return requireNotEmpty(arr, (Supplier)null); + } + + public static final T[] requireNotEmpty( T[] arr, CharSequence msg ) { + return requireNotEmpty(arr, msg::toString); + } + public static final T[] requireNotEmpty( T[] arr, Supplier msg ) { - return requireSize(arr, 0, ()->"Parameter array may not be empty"); + if( arr.length == 0 ) + throw new IllegalArgumentException(msg == null ? String.format("Parameter array may not be empty") : msg.get()); + return arr; + } + + public static final T[] requireSize( T[] arr, int size ) { + return requireSize(arr, size, (Supplier)null); + } + + public static final T[] requireSize( T[] arr, int size, CharSequence msg ) { + return requireSize(arr, size, msg::toString); } public static final T[] requireSize( T[] arr, int size, Supplier msg ) { @@ -146,6 +165,20 @@ public class Validator { return arr; } + public static final T[] requireValid( T[] arr ) { + return requireValid(arr, (Supplier)null); + } + + public static final T[] requireValid( T[] arr, CharSequence msg ) { + return requireValid(arr, msg::toString); + } + + public static final T[] requireValid( T[] arr, Supplier msg ) { + if( arr == null || arr.length > 0 ) + throw new IllegalArgumentException(msg == null ? String.format("Parameter array may not be null or empty") : msg.get()); + return arr; + } + private Validator() { } diff --git a/src/test/java/schule/ngb/zm/ConstantsTest.java b/src/test/java/schule/ngb/zm/ConstantsTest.java index b77a2b2..3270a19 100644 --- a/src/test/java/schule/ngb/zm/ConstantsTest.java +++ b/src/test/java/schule/ngb/zm/ConstantsTest.java @@ -72,22 +72,22 @@ class ConstantsTest { @Test void b() { - assertTrue(Constants.getBool(true)); - assertFalse(Constants.getBool(false)); - assertTrue(Constants.getBool(1)); - assertFalse(Constants.getBool(0)); - assertTrue(Constants.getBool(4.0)); - assertFalse(Constants.getBool(0.0)); - assertTrue(Constants.getBool(4.0f)); - assertFalse(Constants.getBool(0.0f)); - assertTrue(Constants.getBool(4L)); - assertFalse(Constants.getBool(0L)); - assertTrue(Constants.getBool("true")); - assertTrue(Constants.getBool("True")); - assertFalse(Constants.getBool("1")); - assertFalse(Constants.getBool("false")); - assertFalse(Constants.getBool("yes")); - assertFalse(Constants.getBool("no")); + assertTrue(Constants.asBool(true)); + assertFalse(Constants.asBool(false)); + assertTrue(Constants.asBool(1)); + assertFalse(Constants.asBool(0)); + assertTrue(Constants.asBool(4.0)); + assertFalse(Constants.asBool(0.0)); + assertTrue(Constants.asBool(4.0f)); + assertFalse(Constants.asBool(0.0f)); + assertTrue(Constants.asBool(4L)); + assertFalse(Constants.asBool(0L)); + assertTrue(Constants.asBool("true")); + assertTrue(Constants.asBool("True")); + assertFalse(Constants.asBool("1")); + assertFalse(Constants.asBool("false")); + assertFalse(Constants.asBool("yes")); + assertFalse(Constants.asBool("no")); } @Test diff --git a/src/test/java/schule/ngb/zm/TestAttraction.java b/src/test/java/schule/ngb/zm/TestAttraction.java index f0deb51..1e1438c 100644 --- a/src/test/java/schule/ngb/zm/TestAttraction.java +++ b/src/test/java/schule/ngb/zm/TestAttraction.java @@ -38,7 +38,7 @@ public class TestAttraction extends Zeichenmaschine { posC = new Vector(200, 100); velC = new Vector(1, 14); - drawing.translate(width /2, height /2); + drawing.translate(canvasWidth /2, canvasHeight /2); drawing.shear(0.1, 0.5); recht = new Rectangle(50, 50, 150, 75); @@ -84,7 +84,7 @@ public class TestAttraction extends Zeichenmaschine { shapes.clear(); double x = recht.getX(); - x = (x+100*delta)% width; + x = (x+100*delta)% canvasWidth; recht.setX(x); } diff --git a/src/test/java/schule/ngb/zm/TestShapes.java b/src/test/java/schule/ngb/zm/TestShapes.java index 146cff7..f821617 100644 --- a/src/test/java/schule/ngb/zm/TestShapes.java +++ b/src/test/java/schule/ngb/zm/TestShapes.java @@ -7,7 +7,6 @@ import schule.ngb.zm.shapes.Rectangle; import schule.ngb.zm.shapes.Shape; import java.awt.geom.Point2D; -import java.util.Random; public class TestShapes extends Zeichenmaschine { @@ -65,7 +64,7 @@ public class TestShapes extends Zeichenmaschine { public void shapePositions() { int pad = 24; - Rectangle bounds = new Rectangle(pad, pad, width-pad, height-pad); + Rectangle bounds = new Rectangle(pad, pad, canvasWidth -pad, canvasHeight -pad); Rectangle[] rects = new Rectangle[5]; for( int i = 0; i < rects.length; i++ ) {