mirror of
https://github.com/jneug/zeichenmaschine.git
synced 2026-10-12 09:56:33 +02:00
Compare commits
11 Commits
c7e1eb11ed
...
v0.0.34-SN
| Author | SHA1 | Date | |
|---|---|---|---|
| d500c130ed | |||
| b4d390cd9b | |||
| 97ea610f34 | |||
| e2e1f24e3e | |||
| a09b956b48 | |||
| c92a4517b3 | |||
| 1260a38bb7 | |||
| 20772da813 | |||
| 8898d6e8ee | |||
| cb0ee9c842 | |||
| 3cf7871591 |
@@ -6,6 +6,14 @@ und diese Projekt folgt [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## Version 0.0.34
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- `Faker`-Klasse zur Erzeugung von Fake-Daten hinzugefügt.
|
||||||
|
- Dokumentation unter [zeichenmaschine.xyz](https://zeichenmaschine.xyz) mit
|
||||||
|
[MkDocs](https://www.mkdocs.org) und [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/).
|
||||||
|
- Neue `image` methoden im `DrawingLayer`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- `FilledShape` und `StrokedShape` durch `Fillable` und `Strokeable` Interfaces ersetzt.
|
- `FilledShape` und `StrokedShape` durch `Fillable` und `Strokeable` Interfaces ersetzt.
|
||||||
- `Shape` erweitert nun `BasisDrawable` als abstrakte Grundlage.
|
- `Shape` erweitert nun `BasisDrawable` als abstrakte Grundlage.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group 'schule.ngb'
|
group 'schule.ngb'
|
||||||
version '0.0.32-SNAPSHOT'
|
version '0.0.34-SNAPSHOT'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
@@ -44,4 +44,5 @@ tasks.register('jarMP3SPI', Jar) {
|
|||||||
from {
|
from {
|
||||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
}
|
}
|
||||||
|
with jar
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ und für Schülerinnen und Schüler im Unterricht nutzbar machen.
|
|||||||
|
|
||||||
## Dokumentation
|
## Dokumentation
|
||||||
* [Schnellstart](quickstart.md)
|
* [Schnellstart](quickstart.md)
|
||||||
* [Installation](install.md)
|
* [Installation](installation.md)
|
||||||
* {{ javadoc_link() }}
|
* {{ javadoc_link() }}
|
||||||
|
|
||||||
## Über die Zeichenmaschine
|
## Über die Zeichenmaschine
|
||||||
@@ -42,3 +42,5 @@ Projekt in den Classpath aufgenommen werden:
|
|||||||
### NetBeans
|
### NetBeans
|
||||||
|
|
||||||
> Coming soon
|
> Coming soon
|
||||||
|
|
||||||
|
## Unterstützung für MP3
|
||||||
@@ -50,7 +50,6 @@ def define_env(env):
|
|||||||
# _target = re.sub(r"([^(][^,]*?\.)*?([^)]+)", lambda m: m.group(2), target)
|
# _target = re.sub(r"([^(][^,]*?\.)*?([^)]+)", lambda m: m.group(2), target)
|
||||||
_target = target
|
_target = target
|
||||||
|
|
||||||
print(f'{_target.strip()=}')
|
|
||||||
if m := re.match(r'^(.+?)\((.*)\)$', _target):
|
if m := re.match(r'^(.+?)\((.*)\)$', _target):
|
||||||
if strip_params and m.group(2):
|
if strip_params and m.group(2):
|
||||||
params = m.group(2).split(',')
|
params = m.group(2).split(',')
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ die [JAR-Datei der aktuellen Version](https://github.com/jneug/zeichenmaschine/r
|
|||||||
herunterzuladen und
|
herunterzuladen und
|
||||||
dem [Classpath](https://www.delftstack.com/de/howto/java/java-classpath-/)
|
dem [Classpath](https://www.delftstack.com/de/howto/java/java-classpath-/)
|
||||||
hinzuzufügen. Eine Beschreibung für verschiedene Entwicklungsumgebungen findet
|
hinzuzufügen. Eine Beschreibung für verschiedene Entwicklungsumgebungen findet
|
||||||
sich im Abschnitt [Installation](install.md).
|
sich im Abschnitt [Installation](installation.md).
|
||||||
|
|
||||||
## Die Basisklasse
|
## Die Basisklasse
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ extra_css:
|
|||||||
- assets/zmstyles.css
|
- assets/zmstyles.css
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
- Einführung: index.md
|
- Einführung: einfuehrung.md
|
||||||
- Schnellstart: quickstart.md
|
- Schnellstart: schnellstart.md
|
||||||
- Installation: install.md
|
- Installation: installation.md
|
||||||
- Tutorials:
|
- Tutorials:
|
||||||
- Aquarium: tutorials/aquarium/aquarium1.md
|
- Aquarium: tutorials/aquarium/aquarium1.md
|
||||||
- Beispiele:
|
- Beispiele:
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package schule.ngb.zm;
|
package schule.ngb.zm;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.MultipleGradientPaint;
|
||||||
|
import java.awt.Paint;
|
||||||
|
import java.awt.Stroke;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basisimplementierung der {@link Strokeable} und {@link Fillable} APIs.
|
* Basisimplementierung der {@link Strokeable} und {@link Fillable} APIs.
|
||||||
@@ -90,9 +93,6 @@ public abstract class BasicDrawable extends Constants implements Strokeable, Fil
|
|||||||
|
|
||||||
// Implementierung Fillable Interface
|
// Implementierung Fillable Interface
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setFill( Paint fill ) {
|
public void setFill( Paint fill ) {
|
||||||
if( fill == null ) {
|
if( fill == null ) {
|
||||||
@@ -106,9 +106,6 @@ public abstract class BasicDrawable extends Constants implements Strokeable, Fil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Paint getFill() {
|
public Paint getFill() {
|
||||||
if( fill != null ) {
|
if( fill != null ) {
|
||||||
@@ -120,42 +117,27 @@ public abstract class BasicDrawable extends Constants implements Strokeable, Fil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFillColor() {
|
public boolean hasFillColor() {
|
||||||
return fillColor != null;
|
return fillColor != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasGradient() {
|
public boolean hasGradient() {
|
||||||
return fill != null;
|
return fill != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Color getFillColor() {
|
public Color getFillColor() {
|
||||||
return fillColor;
|
return fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setFillColor( Color color ) {
|
public void setFillColor( Color color ) {
|
||||||
fillColor = color;
|
fillColor = color;
|
||||||
fill = null;
|
fill = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MultipleGradientPaint getGradient() {
|
public MultipleGradientPaint getGradient() {
|
||||||
return fill;
|
return fill;
|
||||||
@@ -164,17 +146,11 @@ public abstract class BasicDrawable extends Constants implements Strokeable, Fil
|
|||||||
|
|
||||||
// Implementierung Strokeable Interface
|
// Implementierung Strokeable Interface
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setStroke( Stroke stroke ) {
|
public void setStroke( Stroke stroke ) {
|
||||||
this.stroke = stroke;
|
this.stroke = stroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Stroke getStroke() {
|
public Stroke getStroke() {
|
||||||
if( stroke == null ) {
|
if( stroke == null ) {
|
||||||
@@ -183,50 +159,32 @@ public abstract class BasicDrawable extends Constants implements Strokeable, Fil
|
|||||||
return stroke;
|
return stroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Color getStrokeColor() {
|
public Color getStrokeColor() {
|
||||||
return strokeColor;
|
return strokeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setStrokeColor( Color color ) {
|
public void setStrokeColor( Color color ) {
|
||||||
strokeColor = color;
|
strokeColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getStrokeWeight() {
|
public double getStrokeWeight() {
|
||||||
return strokeWeight;
|
return strokeWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setStrokeWeight( double weight ) {
|
public void setStrokeWeight( double weight ) {
|
||||||
strokeWeight = weight;
|
strokeWeight = weight;
|
||||||
this.stroke = null;
|
this.stroke = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Options.StrokeType getStrokeType() {
|
public Options.StrokeType getStrokeType() {
|
||||||
return strokeType;
|
return strokeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setStrokeType( Options.StrokeType type ) {
|
public void setStrokeType( Options.StrokeType type ) {
|
||||||
strokeType = type;
|
strokeType = type;
|
||||||
|
|||||||
@@ -88,7 +88,11 @@ public abstract class Layer extends Constants implements Drawable, Updatable {
|
|||||||
} else {
|
} else {
|
||||||
createCanvas(width, height);
|
createCanvas(width, height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: prevent access to graphics context?
|
||||||
|
public Graphics2D getGraphics() {
|
||||||
|
return this.drawing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,9 +169,6 @@ public abstract class Layer extends Constants implements Drawable, Updatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return visible;
|
return visible;
|
||||||
@@ -197,16 +198,10 @@ public abstract class Layer extends Constants implements Drawable, Updatable {
|
|||||||
visible = !visible;
|
visible = !visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void update( double delta ) {
|
public void update( double delta ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return active;
|
return active;
|
||||||
|
|||||||
@@ -57,9 +57,6 @@ public class ColorLayer extends Layer {
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setSize( int width, int height ) {
|
public void setSize( int width, int height ) {
|
||||||
super.setSize(width, height);
|
super.setSize(width, height);
|
||||||
|
|||||||
@@ -87,9 +87,6 @@ public class DrawableLayer extends Layer {
|
|||||||
this.clearBeforeDraw = pClearBeforeDraw;
|
this.clearBeforeDraw = pClearBeforeDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void draw( Graphics2D graphics ) {
|
public void draw( Graphics2D graphics ) {
|
||||||
if( clearBeforeDraw ) {
|
if( clearBeforeDraw ) {
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package schule.ngb.zm.layers;
|
package schule.ngb.zm.layers;
|
||||||
|
|
||||||
import schule.ngb.zm.Color;
|
import schule.ngb.zm.Color;
|
||||||
import schule.ngb.zm.Layer;
|
import schule.ngb.zm.*;
|
||||||
import schule.ngb.zm.Options;
|
|
||||||
import schule.ngb.zm.Fillable;
|
|
||||||
import schule.ngb.zm.Strokeable;
|
|
||||||
import schule.ngb.zm.shapes.Text;
|
import schule.ngb.zm.shapes.Text;
|
||||||
import schule.ngb.zm.util.io.ImageLoader;
|
import schule.ngb.zm.util.io.ImageLoader;
|
||||||
|
|
||||||
@@ -418,9 +415,6 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
shapeDelegate.setStrokeType(type);
|
shapeDelegate.setStrokeType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Stroke getStroke() {
|
public Stroke getStroke() {
|
||||||
return shapeDelegate.getStroke();
|
return shapeDelegate.getStroke();
|
||||||
@@ -944,7 +938,7 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeichnet das Bild von der angegebenen Quelle an der angegebenen Position
|
* Zeichnet das Bild von der angegebenen Quelle an der angegebenen Position
|
||||||
* auf dei Zeichenebene.
|
* auf die Zeichenebene.
|
||||||
* <p>
|
* <p>
|
||||||
* Die Bildquelle wird mithilfe von {@link ImageLoader#loadImage(String)}
|
* Die Bildquelle wird mithilfe von {@link ImageLoader#loadImage(String)}
|
||||||
* geladen. Schlägt dies fehl, wird nichts gezeichnet.
|
* geladen. Schlägt dies fehl, wird nichts gezeichnet.
|
||||||
@@ -952,6 +946,7 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
* @param imageSource Die Bildquelle.
|
* @param imageSource Die Bildquelle.
|
||||||
* @param x x-Koordinate des Ankerpunktes.
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
* @param y y-Koordinate des Ankerpunktes.
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
*/
|
*/
|
||||||
public void image( String imageSource, double x, double y ) {
|
public void image( String imageSource, double x, double y ) {
|
||||||
image(ImageLoader.loadImage(imageSource), x, y, 1.0, shapeDelegate.getAnchor());
|
image(ImageLoader.loadImage(imageSource), x, y, 1.0, shapeDelegate.getAnchor());
|
||||||
@@ -959,7 +954,7 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeichnet das Bild von der angegebenen Quelle an der angegebenen Position
|
* Zeichnet das Bild von der angegebenen Quelle an der angegebenen Position
|
||||||
* auf dei Zeichenebene.
|
* auf die Zeichenebene.
|
||||||
* <p>
|
* <p>
|
||||||
* Die Bildquelle wird mithilfe von {@link ImageLoader#loadImage(String)}
|
* Die Bildquelle wird mithilfe von {@link ImageLoader#loadImage(String)}
|
||||||
* geladen. Schlägt dies fehl, wird nichts gezeichnet.
|
* geladen. Schlägt dies fehl, wird nichts gezeichnet.
|
||||||
@@ -967,47 +962,73 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
* @param imageSource Die Bildquelle.
|
* @param imageSource Die Bildquelle.
|
||||||
* @param x x-Koordinate des Ankerpunktes.
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
* @param y y-Koordinate des Ankerpunktes.
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
* @param anchor
|
* @param anchor Der Ankerpunkt.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
*/
|
*/
|
||||||
public void image( String imageSource, double x, double y, Options.Direction anchor ) {
|
public void image( String imageSource, double x, double y, Options.Direction anchor ) {
|
||||||
image(ImageLoader.loadImage(imageSource), x, y, 1.0, anchor);
|
image(ImageLoader.loadImage(imageSource), x, y, 1.0, anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param imageSource
|
* Zeichnet das Bild von der angegebenen Quelle an den angegebenen
|
||||||
* @param x
|
* Koordinaten auf die Zeichenebene. Das Bild wird um den angegebenen Faktor
|
||||||
* @param y
|
* skaliert.
|
||||||
* @param scale
|
* <p>
|
||||||
|
* Siehe {@link #image(Image, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param imageSource Die Bildquelle.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param scale Der Skalierungsfaktor des Bildes.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
*/
|
*/
|
||||||
public void image( String imageSource, double x, double y, double scale ) {
|
public void image( String imageSource, double x, double y, double scale ) {
|
||||||
image(ImageLoader.loadImage(imageSource), x, y, scale, shapeDelegate.getAnchor());
|
image(ImageLoader.loadImage(imageSource), x, y, scale, shapeDelegate.getAnchor());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param imageSource
|
* Zeichnet das Bild von der angegebenen Quelle an den angegebenen
|
||||||
* @param x
|
* Koordinaten auf die Zeichenebene. Das Bild wird um den angegebenen Faktor
|
||||||
* @param y
|
* skaliert und der angegebene Ankerpunkt verwendet.
|
||||||
* @param scale
|
* <p>
|
||||||
* @param anchor
|
* Siehe {@link #image(Image, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param imageSource Die Bildquelle.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param scale Der Skalierungsfaktor des Bildes.
|
||||||
|
* @param anchor Der Ankerpunkt.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
*/
|
*/
|
||||||
public void image( String imageSource, double x, double y, double scale, Options.Direction anchor ) {
|
public void image( String imageSource, double x, double y, double scale, Options.Direction anchor ) {
|
||||||
image(ImageLoader.loadImage(imageSource), x, y, scale, anchor);
|
image(ImageLoader.loadImage(imageSource), x, y, scale, anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param image
|
* Zeichnet das angegebene Bild an den angegebenen Koordinaten auf die
|
||||||
* @param x
|
* Zeichenebene.
|
||||||
* @param y
|
*
|
||||||
|
* @param image Das vorher geladene Bild.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
*/
|
*/
|
||||||
public void image( Image image, double x, double y ) {
|
public void image( Image image, double x, double y ) {
|
||||||
image(image, x, y, 1.0, shapeDelegate.getAnchor());
|
image(image, x, y, 1.0, shapeDelegate.getAnchor());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param image
|
* Zeichnet das angegebene Bild an den angegebenen Koordinaten auf die
|
||||||
* @param x
|
* Zeichenebene. Das Bild wird um den angegebenen Faktor skaliert.
|
||||||
* @param y
|
* <p>
|
||||||
* @param scale
|
* Siehe {@link #image(Image, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param image Das vorher geladene Bild.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param scale Der Skalierungsfaktor des Bildes.
|
||||||
*/
|
*/
|
||||||
public void image( Image image, double x, double y, double scale ) {
|
public void image( Image image, double x, double y, double scale ) {
|
||||||
image(image, x, y, scale, shapeDelegate.getAnchor());
|
image(image, x, y, scale, shapeDelegate.getAnchor());
|
||||||
@@ -1015,8 +1036,18 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeichnet das angegebene Bild an den angegebenen Koordinaten auf die
|
* Zeichnet das angegebene Bild an den angegebenen Koordinaten auf die
|
||||||
* Zeichenebene. Das Bild wird skaliert und der angegebene Ankerpunkt
|
* Zeichenebene. Das Bild wird um den angegebenen Faktor skaliert und der
|
||||||
* verwendet.
|
* angegebene Ankerpunkt verwendet.
|
||||||
|
* <p>
|
||||||
|
* Bei einem Faktor größer 0 wird das Bild vergrößert, bei einem Faktor
|
||||||
|
* kleiner 0 verkleinert. Bei negativen Werten wird das Bild entlang der x-
|
||||||
|
* bzw. y-Achse gespiegelt.
|
||||||
|
* <p>
|
||||||
|
* Das Seitenverhältnis wird immer beibehalten.
|
||||||
|
* <p>
|
||||||
|
* Soll das Bild innerhalb eines vorgegebenen Rechtecks liegen, sollte
|
||||||
|
* {@link #image(Image, double, double, double, double, Options.Direction)}
|
||||||
|
* verwendet werden.
|
||||||
*
|
*
|
||||||
* @param image Das vorher geladene Bild.
|
* @param image Das vorher geladene Bild.
|
||||||
* @param x x-Koordinate des Ankerpunktes.
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
@@ -1025,16 +1056,116 @@ public class DrawingLayer extends Layer implements Strokeable, Fillable {
|
|||||||
* @param anchor Der Ankerpunkt.
|
* @param anchor Der Ankerpunkt.
|
||||||
*/
|
*/
|
||||||
public void image( Image image, double x, double y, double scale, Options.Direction anchor ) {
|
public void image( Image image, double x, double y, double scale, Options.Direction anchor ) {
|
||||||
if( image != null ) {
|
/*if( image != null ) {
|
||||||
double neww = image.getWidth(null) * scale;
|
double neww = image.getWidth(null) * scale;
|
||||||
double newh = image.getHeight(null) * scale;
|
double newh = image.getHeight(null) * scale;
|
||||||
Point2D.Double anchorPoint = getOriginPoint(x, y, neww, newh, anchor);
|
Point2D.Double anchorPoint = getOriginPoint(x, y, neww, newh, anchor);
|
||||||
drawing.drawImage(image, (int) anchorPoint.x, (int) anchorPoint.y, (int) neww, (int) newh, null);
|
drawing.drawImage(image, (int) anchorPoint.x, (int) anchorPoint.y, (int) neww, (int) newh, null);
|
||||||
|
}*/
|
||||||
|
double neww = image.getWidth(null) * scale;
|
||||||
|
double newh = image.getHeight(null) * scale;
|
||||||
|
image(image, x, y, neww, newh, anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet das Bild von der angegebenen Quelle an den angegebenen
|
||||||
|
* Koordinaten in der angegebenen Größe auf die Zeichenebene.
|
||||||
|
* <p>
|
||||||
|
* Siehe
|
||||||
|
* {@link #image(Image, double, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param imageSource Die Bildquelle.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param width Breite des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param height Höhe des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
|
*/
|
||||||
|
public void image( String imageSource, double x, double y, double width, double height ) {
|
||||||
|
image(ImageLoader.loadImage(imageSource), x, y, width, height, shapeDelegate.getAnchor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet das Bild von der angegebenen Quelle an den angegebenen
|
||||||
|
* Koordinaten in der angegebenen Größe auf die Zeichenebene. Es wird der
|
||||||
|
* angegebene Ankerpunkt verwendet.
|
||||||
|
* <p>
|
||||||
|
* Siehe
|
||||||
|
* {@link #image(Image, double, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param imageSource Die Bildquelle.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param width Breite des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param height Höhe des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param anchor Der Ankerpunkt.
|
||||||
|
* @see ImageLoader#loadImage(String)
|
||||||
|
*/
|
||||||
|
public void image( String imageSource, double x, double y, double width, double height, Options.Direction anchor ) {
|
||||||
|
image(ImageLoader.loadImage(imageSource), x, y, width, height, anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet das angegebene Bild an den angegebenen Koordinaten in der
|
||||||
|
* angegebenen Größe auf die Zeichenebene.
|
||||||
|
* <p>
|
||||||
|
* Siehe
|
||||||
|
* {@link #image(Image, double, double, double, double, Options.Direction)}
|
||||||
|
* für mehr Details.
|
||||||
|
*
|
||||||
|
* @param image Ein Bild-Objekt.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param width Breite des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param height Höhe des Bildes auf der Zeichenebene oder 0.
|
||||||
|
*/
|
||||||
|
public void image( Image image, double x, double y, double width, double height ) {
|
||||||
|
image(image, x, y, width, height, shapeDelegate.getAnchor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet das angegebene Bild an den angegebenen Koordinaten in der
|
||||||
|
* angegebenen Größe auf die Zeichenebene. Der angegebene Ankerpunkt wird
|
||||||
|
* verwendet.
|
||||||
|
* <p>
|
||||||
|
* Das Bild wird innerhalb eines Rechtecks mit der angegebenen Breite und
|
||||||
|
* Höhe gezeichnet. Dabei wird das Abbild verzerrt, wenn beim Aufruf nicht
|
||||||
|
* auf ein passendes Seitenverhältnis der Werte zueinander geachtet wird.
|
||||||
|
* <p>
|
||||||
|
* Um das Bild auf eine bestimmte Breite oder Höhe festzulegen und die
|
||||||
|
* andere Größe passend zu skalieren, kann einer der Parameter auf 0 gesetzt
|
||||||
|
* werden.
|
||||||
|
* <p>
|
||||||
|
* Soll die Bildgröße unter Beachtung der Abmessungen um einen Faktor
|
||||||
|
* verändert werden, sollte
|
||||||
|
* {@link #image(Image, double, double, double, Options.Direction)}
|
||||||
|
* verwendet werden.
|
||||||
|
*
|
||||||
|
* @param image Ein Bild-Objekt.
|
||||||
|
* @param x x-Koordinate des Ankerpunktes.
|
||||||
|
* @param y y-Koordinate des Ankerpunktes.
|
||||||
|
* @param width Breite des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param height Höhe des Bildes auf der Zeichenebene oder 0.
|
||||||
|
* @param anchor Der Ankerpunkt.
|
||||||
|
*/
|
||||||
|
public void image( Image image, double x, double y, double width, double height, Options.Direction anchor ) {
|
||||||
|
// TODO: Use Validator or at least LOG a message if image == null?
|
||||||
|
if( image != null ) {
|
||||||
|
if( width == 0 ) {
|
||||||
|
width = (height / image.getHeight(null)) * image.getWidth(null);
|
||||||
|
} else if( height == 0 ) {
|
||||||
|
height = (width / image.getWidth(null)) * image.getHeight(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2D.Double anchorPoint = getOriginPoint(x, y, width, height, anchor);
|
||||||
|
drawing.drawImage(image, (int) anchorPoint.x, (int) anchorPoint.y, (int) width, (int) height, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Git aktuelle verwendete Schriftart.
|
* @return Die aktuell verwendete Schriftart.
|
||||||
*/
|
*/
|
||||||
public Font getFont() {
|
public Font getFont() {
|
||||||
return shapeDelegate.getFont();
|
return shapeDelegate.getFont();
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
package schule.ngb.zm.media;
|
package schule.ngb.zm.media;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface für Audio-Medien.
|
* Schnittstelle für Audio-Medien.
|
||||||
|
*
|
||||||
|
* <h2>MP3-Dateien verwenden</h2>
|
||||||
|
* Java kann nativ nur Waveform ({@code .wav}) Dateien wiedergeben. Um auch
|
||||||
|
* MP3-Dateien zu nutzen, müssen die Bibliotheken <a href="#">jlayer</a>, <a
|
||||||
|
* href="#">tritonus-share</a> und <a href="#">mp3spi</a> eingebunden werden.
|
||||||
|
* Details zur Verwendung können in der <a
|
||||||
|
* href="https://zeichenmaschine.xyz/installation/#unterstutzung-fur-mp3">Dokumentation
|
||||||
|
* der Zeichenmaschine</a> nachgelesen werden.
|
||||||
*/
|
*/
|
||||||
public interface Audio {
|
public interface Audio {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Die Quelle, aus der das Medium geladen wurde.
|
||||||
|
*/
|
||||||
String getSource();
|
String getSource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,7 +28,7 @@ public interface Audio {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prüft, ob das Medium gerade in einer Schleife abgespielt wird. Wenn
|
* Prüft, ob das Medium gerade in einer Schleife abgespielt wird. Wenn
|
||||||
* {@code isLooping() == true}, dann muss auch immer
|
* {@code isLooping() == true} gilt, dann muss auch immer
|
||||||
* {@code isPlaying() == true} gelten.
|
* {@code isPlaying() == true} gelten.
|
||||||
*
|
*
|
||||||
* @return {@code true}, wenn das Medium in einer Schleife abgespielt wird,
|
* @return {@code true}, wenn das Medium in einer Schleife abgespielt wird,
|
||||||
@@ -30,7 +41,7 @@ public interface Audio {
|
|||||||
* <p>
|
* <p>
|
||||||
* Die Lautstärke wird auf einer linearen Skale festgelegt, wobei 0 kein Ton
|
* Die Lautstärke wird auf einer linearen Skale festgelegt, wobei 0 kein Ton
|
||||||
* und 1 volle Lautstärke bedeutet. Werte über 1 verstärken den Ton des
|
* und 1 volle Lautstärke bedeutet. Werte über 1 verstärken den Ton des
|
||||||
* Mediums.
|
* Mediums. Negative Werte setzen die Lautstärke aud 0.
|
||||||
*
|
*
|
||||||
* @param volume Die neue Lautstärke zwischen 0 und 1.
|
* @param volume Die neue Lautstärke zwischen 0 und 1.
|
||||||
* @see <a
|
* @see <a
|
||||||
@@ -39,7 +50,7 @@ public interface Audio {
|
|||||||
void setVolume( double volume );
|
void setVolume( double volume );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gibt die aktuelle Lautstärkeeinstellung dieses Mediums zurück.
|
* Liefert die aktuelle Lautstärke dieses Mediums.
|
||||||
* <p>
|
* <p>
|
||||||
* Die Lautstärke wird auf einer linearen Skale angegeben, wobei 0 kein Ton
|
* Die Lautstärke wird auf einer linearen Skale angegeben, wobei 0 kein Ton
|
||||||
* und 1 volle Lautstärke bedeutet. Werte über 1 verstärken den Ton des
|
* und 1 volle Lautstärke bedeutet. Werte über 1 verstärken den Ton des
|
||||||
@@ -50,8 +61,16 @@ public interface Audio {
|
|||||||
double getVolume();
|
double getVolume();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Startet die Wiedergabe des Mediums und beendet die Methode. Das
|
* Startet die Wiedergabe des Mediums. Das Audio-Medium wird einmal
|
||||||
* Audio-Medium wird einmal abgespielt und stoppt dann.
|
* abgespielt und stoppt dann.
|
||||||
|
* <p>
|
||||||
|
* Die Methode beendet sofort und die Wiedergabe erfolgt im Hintergrund.
|
||||||
|
* Soll die Programmausführung erst nach Wiedergabe des Mediums fortgesetzt
|
||||||
|
* werden, sollte {@link #playAndWait()} verwendet werden.
|
||||||
|
* <p>
|
||||||
|
* Soll die Wiedergabe im Hintergrund ablaufen, aber dennoch auf das Ende
|
||||||
|
* reagiert werden, kann ein
|
||||||
|
* {@link #addAudioListener(AudioListener) AudioListener} verwendet werden.
|
||||||
*/
|
*/
|
||||||
void play();
|
void play();
|
||||||
|
|
||||||
@@ -63,28 +82,28 @@ public interface Audio {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Spielt das Medium in einer kontinuierlichen Schleife ab. Die Methode
|
* Spielt das Medium in einer kontinuierlichen Schleife ab. Die Methode
|
||||||
* startet die Wiedergabe und beendet dann direkt die Methode. Um die
|
* startet die Wiedergabe im Hintergrund und beendet dann sofort. Um die
|
||||||
* Wiedergabe zu stoppen muss {@link #stop()} aufgerufen werden.
|
* Wiedergabe zu stoppen, muss {@link #stop()} aufgerufen werden.
|
||||||
*/
|
*/
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stoppt die Wiedergabe. Wird das Medium gerade nicht abgespielt
|
* Stoppt die Wiedergabe. Wird das Medium gerade nicht abgespielt
|
||||||
* {@code isPlaying() == false}, dann passiert nichts.
|
* ({@code isPlaying() == false}), dann passiert nichts.
|
||||||
*/
|
*/
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stoppt die Wiedergabe und gibt alle Resourcen, die für das Medium
|
* Stoppt die Wiedergabe und gibt alle Ressourcen, die für das Medium
|
||||||
* verwendet werden, frei.
|
* verwendet werden, frei.
|
||||||
*/
|
*/
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fügt dem Medium das angegbene Objekt als {@code AudioListener} hinzu, der
|
* Fügt dem Medium das angegebene Objekt als {@code AudioListener} hinzu,
|
||||||
* bei Start und Stopp der Wiedergabe informiert werden soll.
|
* der bei Start und Stopp der Wiedergabe informiert wird.
|
||||||
*
|
*
|
||||||
* @param listener Das zu informierende Objekt.
|
* @param listener Das Listener-Objekt.
|
||||||
*/
|
*/
|
||||||
void addAudioListener( AudioListener listener );
|
void addAudioListener( AudioListener listener );
|
||||||
|
|
||||||
|
|||||||
@@ -14,20 +14,20 @@ import schule.ngb.zm.util.events.Listener;
|
|||||||
public interface AudioListener extends Listener<Audio> {
|
public interface AudioListener extends Listener<Audio> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wird aufgerufen, sobald die Wiedergabe eines Audio-Objektes startet, dem
|
* Wird aufgerufen, sobald die Wiedergabe eines Audio-Mediums startet, dem
|
||||||
* dieses Objekt mittels {@link Audio#addAudioListener(AudioListener)}
|
* dieses Objekt mittels {@link Audio#addAudioListener(AudioListener)}
|
||||||
* hinzugefügt wurde.
|
* hinzugefügt wurde.
|
||||||
*
|
*
|
||||||
* @param source Das Audio-Objekt, dessen Wiedergabe gestartet wurde.
|
* @param source Das Audio-Medium, dessen Wiedergabe gestartet wurde.
|
||||||
*/
|
*/
|
||||||
void playbackStarted( Audio source );
|
void playbackStarted( Audio source );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wird aufgerufen, sobald die Wiedergabe eines Audio-Objektes stoppt, dem
|
* Wird aufgerufen, sobald die Wiedergabe eines Audio-Mediums stoppt, dem
|
||||||
* dieses Objekt mittels {@link Audio#addAudioListener(AudioListener)}
|
* dieses Objekt mittels {@link Audio#addAudioListener(AudioListener)}
|
||||||
* hinzugefügt wurde.
|
* hinzugefügt wurde.
|
||||||
*
|
*
|
||||||
* @param source Das Audio-Objekt, dessen Wiedergabe gestoppt wurde.
|
* @param source Das Audio-Medium, dessen Wiedergabe gestoppt wurde.
|
||||||
*/
|
*/
|
||||||
void playbackStopped( Audio source );
|
void playbackStopped( Audio source );
|
||||||
|
|
||||||
|
|||||||
@@ -98,50 +98,32 @@ public class Mixer implements Audio, AudioListener {
|
|||||||
audios.clear();
|
audios.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPlaying() {
|
public boolean isPlaying() {
|
||||||
return audios.stream().anyMatch(aw -> aw.audio.isPlaying());
|
return audios.stream().anyMatch(aw -> aw.audio.isPlaying());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLooping() {
|
public boolean isLooping() {
|
||||||
return audios.stream().anyMatch(aw -> aw.audio.isLooping());
|
return audios.stream().anyMatch(aw -> aw.audio.isLooping());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setVolume( double pVolume ) {
|
public void setVolume( double volume ) {
|
||||||
volume = (float) pVolume;
|
this.volume = volume < 0 ? 0f : (float) volume;
|
||||||
audios.stream().forEach(aw -> aw.audio.setVolume(aw.volumeFactor * pVolume));
|
audios.stream().forEach(aw -> aw.audio.setVolume(aw.volumeFactor * volume));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getVolume() {
|
public double getVolume() {
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void play() {
|
public void play() {
|
||||||
audios.stream().forEach(aw -> aw.audio.play());
|
audios.stream().forEach(aw -> aw.audio.play());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void playAndWait() {
|
public void playAndWait() {
|
||||||
audios.stream().forEach(aw -> aw.audio.play());
|
audios.stream().forEach(aw -> aw.audio.play());
|
||||||
@@ -154,25 +136,16 @@ public class Mixer implements Audio, AudioListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void loop() {
|
public void loop() {
|
||||||
audios.stream().forEach(aw -> aw.audio.loop());
|
audios.stream().forEach(aw -> aw.audio.loop());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
audios.stream().forEach(aw -> aw.audio.stop());
|
audios.stream().forEach(aw -> aw.audio.stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if( isPlaying() ) {
|
if( isPlaying() ) {
|
||||||
@@ -243,7 +216,8 @@ public class Mixer implements Audio, AudioListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
||||||
* aufgerufen, soblad sich auch ein Listener registrieren möchte.
|
* aufgerufen, sobald sich auch ein Listener registrieren möchte.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
||||||
|
|||||||
@@ -1,84 +1,103 @@
|
|||||||
package schule.ngb.zm.media;
|
package schule.ngb.zm.media;
|
||||||
|
|
||||||
import schule.ngb.zm.util.events.EventDispatcher;
|
|
||||||
import schule.ngb.zm.util.tasks.TaskRunner;
|
|
||||||
import schule.ngb.zm.util.Log;
|
import schule.ngb.zm.util.Log;
|
||||||
import schule.ngb.zm.util.io.ResourceStreamProvider;
|
|
||||||
import schule.ngb.zm.util.Validator;
|
import schule.ngb.zm.util.Validator;
|
||||||
|
import schule.ngb.zm.util.events.EventDispatcher;
|
||||||
|
import schule.ngb.zm.util.io.ResourceStreamProvider;
|
||||||
|
import schule.ngb.zm.util.tasks.TaskRunner;
|
||||||
|
|
||||||
import javax.sound.sampled.*;
|
import javax.sound.sampled.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ein Musikstück, dass im Projekt abgespielt werden soll.
|
* Eine Musik, die abgespielt werden kann.
|
||||||
* <p>
|
* <p>
|
||||||
* Im gegensatz zu einem {@link Sound} sind Musikstücke längere Audiodateien,
|
* Im Gegensatz zu einem {@link Sound} wird {@code Music} für längere
|
||||||
* die zum Beispiel als Hintergrundmusik ablaufen sollen. Die Musik wird daher
|
* Audiodateien benutzt, die zum Beispiel als Hintergrundmusik gespielt werden.
|
||||||
* nicht komplett in den Speicher geladen, sondern direkt aus der Audioquelle
|
* Die Audiodaten werden daher nicht vollständig in den Speicher geladen,
|
||||||
* gestreamt und wiedergegeben.
|
* sondern direkt aus der Quelle gestreamt und direkt wiedergegeben.
|
||||||
|
* <p>
|
||||||
|
* Daher ist es nicht möglich, die länge der Musik im Vorfeld abzufragen oder zu
|
||||||
|
* einer bestimmten Stelle im Stream zu springen.
|
||||||
|
*
|
||||||
|
* <h2>MP3-Dateien verwenden</h2>
|
||||||
|
* Java kann nativ nur Waveform ({@code .wav}) Dateien wiedergeben. Um auch
|
||||||
|
* MP3-Dateien zu nutzen, müssen die Bibliotheken <a href="#">jlayer</a>, <a
|
||||||
|
* href="#">tritonus-share</a> und <a href="#">mp3spi</a> eingebunden werden.
|
||||||
|
* Details zur Verwendung können in der <a
|
||||||
|
* href="https://zeichenmaschine.xyz/installation/#unterstutzung-fur-mp3">Dokumentation
|
||||||
|
* der Zeichenmaschine</a> nachgelesen werden.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
// TODO: Wann sollten Listener beim Loopen informiert werden? Nach jedem Loop oder erst ganz am Ende?
|
||||||
|
@SuppressWarnings( "unused" )
|
||||||
public class Music implements Audio {
|
public class Music implements Audio {
|
||||||
|
|
||||||
// size of the byte buffer used to read/write the audio stream
|
/**
|
||||||
|
* Größe des verwendeten Input-Puffers für die Audiodaten.
|
||||||
|
*/
|
||||||
private static final int BUFFER_SIZE = 4096;
|
private static final int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ob der Sound gerade abgespielt wird.
|
* Ob der Sound aktuell abgespielt wird.
|
||||||
*/
|
*/
|
||||||
private boolean playing = false;
|
private boolean playing = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ob der Sound gerade in einer Schleife abgespielt wird.
|
* Ob der Sound aktuell in einer Schleife abgespielt wird.
|
||||||
*/
|
*/
|
||||||
private boolean looping = false;
|
private boolean looping = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Quelle des Musikstücks.
|
* Die Quelle der Audiodaten.
|
||||||
*/
|
*/
|
||||||
private String audioSource;
|
private String audioSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Der AudioStream, um die AUdiosdaten zulsen, falls dieser schon geöffnet
|
* Der {@link AudioInputStream}, um die Audiosdaten zu lesen. {@code null},
|
||||||
* wurde. Sonst {@code null}.
|
* falls noch kein Stream geöffnet wurde.
|
||||||
*/
|
*/
|
||||||
private AudioInputStream audioStream;
|
private AudioInputStream audioStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Line für die Ausgabe, falls diese schon geöffnet wurde. Sonst
|
* Die {@link SourceDataLine} für die Ausgabe. {@code null}, falls die
|
||||||
* {@code null}.
|
* Audiodatei noch nicht geöffnet wurde.
|
||||||
*/
|
*/
|
||||||
private SourceDataLine audioLine;
|
private SourceDataLine audioLine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Lautstärke der Musik.
|
* Die aktuelle Lautstärke des Mediums.
|
||||||
*/
|
*/
|
||||||
private float volume = 0.8f;
|
private float volume = 0.8f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatcher für Audio-Events (start und stop).
|
||||||
|
*/
|
||||||
EventDispatcher<Audio, AudioListener> eventDispatcher;
|
EventDispatcher<Audio, AudioListener> eventDispatcher;
|
||||||
|
|
||||||
public Music( String source ) {
|
/**
|
||||||
Validator.requireNotNull(source);
|
* Erstellt eine Musik aus der angegebenen Audioquelle.
|
||||||
this.audioSource = source;
|
*
|
||||||
|
* @param audioSource Quelle der Audiodaten.
|
||||||
|
* @throws NullPointerException Falls die Quelle {@code null} ist.
|
||||||
|
* @see ResourceStreamProvider#getResourceURL(String)
|
||||||
|
*/
|
||||||
|
public Music( String audioSource ) {
|
||||||
|
Validator.requireNotNull(audioSource);
|
||||||
|
this.audioSource = audioSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return audioSource;
|
return audioSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPlaying() {
|
public boolean isPlaying() {
|
||||||
return playing;
|
return playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLooping() {
|
public boolean isLooping() {
|
||||||
if( !playing ) {
|
if( !playing ) {
|
||||||
@@ -87,28 +106,21 @@ public class Music implements Audio {
|
|||||||
return looping;
|
return looping;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setVolume( double volume ) {
|
public void setVolume( double volume ) {
|
||||||
this.volume = (float) volume;
|
this.volume = volume < 0 ? 0f : (float) volume;
|
||||||
if( audioLine != null ) {
|
if( audioLine != null ) {
|
||||||
applyVolume();
|
applyVolume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getVolume() {
|
public double getVolume() {
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, um die gesetzte Lautstärke vor dem Abspielen
|
* Wendet die Lautstärke vor dem Abspielen auf den Audiostream an.
|
||||||
* anzuwenden.
|
|
||||||
*/
|
*/
|
||||||
private void applyVolume() {
|
private void applyVolume() {
|
||||||
FloatControl gainControl =
|
FloatControl gainControl =
|
||||||
@@ -119,24 +131,13 @@ public class Music implements Audio {
|
|||||||
gainControl.setValue(vol);
|
gainControl.setValue(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void play() {
|
public void play() {
|
||||||
if( openLine() ) {
|
if( openLine() ) {
|
||||||
TaskRunner.run(new Runnable() {
|
TaskRunner.run(this::stream);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
stream();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void playAndWait() {
|
public void playAndWait() {
|
||||||
if( openLine() ) {
|
if( openLine() ) {
|
||||||
@@ -144,18 +145,12 @@ public class Music implements Audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void loop() {
|
public void loop() {
|
||||||
looping = true;
|
looping = true;
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
playing = false;
|
playing = false;
|
||||||
@@ -163,9 +158,6 @@ public class Music implements Audio {
|
|||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void dispose() {
|
public synchronized void dispose() {
|
||||||
if( audioLine != null ) {
|
if( audioLine != null ) {
|
||||||
@@ -189,7 +181,17 @@ public class Music implements Audio {
|
|||||||
audioStream = null;
|
audioStream = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Startet den Stream der Audiodaten und damit die Wiedergabe.
|
||||||
|
* <p>
|
||||||
|
* Die {@link #audioLine} muss vorher mit {@link #openLine()} geöffnet
|
||||||
|
* werden, ansonsten passiert nichts.
|
||||||
|
*/
|
||||||
private synchronized void stream() {
|
private synchronized void stream() {
|
||||||
|
if( audioLine == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
audioLine.start();
|
audioLine.start();
|
||||||
playing = true;
|
playing = true;
|
||||||
if( eventDispatcher != null ) {
|
if( eventDispatcher != null ) {
|
||||||
@@ -226,6 +228,14 @@ public class Music implements Audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Öffnet eine {@link SourceDataLine} für die
|
||||||
|
* {@link #audioSource Audioquelle} und bereitet die Wiedergabe vor. Es wird
|
||||||
|
* noch nichts abgespielt.
|
||||||
|
*
|
||||||
|
* @return {@code true}, wenn die Line geöffnet werden konnte, {@code false}
|
||||||
|
* sonst.
|
||||||
|
*/
|
||||||
private boolean openLine() {
|
private boolean openLine() {
|
||||||
if( audioLine != null ) {
|
if( audioLine != null ) {
|
||||||
return true;
|
return true;
|
||||||
@@ -262,6 +272,15 @@ public class Music implements Audio {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wird aufgerufen, wenn die Wiedergabe beendet wurde. Entweder durch einen
|
||||||
|
* Aufruf von {@link #stop()} oder weil keine Audiodaten mehr vorhanden
|
||||||
|
* sind.
|
||||||
|
* <p>
|
||||||
|
* Nach dem Ende des Streams wird {@link #dispose()} aufgerufen und, falls
|
||||||
|
* das Musikstück in einer Schleife abgespielt wird, der Stream direkt
|
||||||
|
* wieder gestartet.
|
||||||
|
*/
|
||||||
private void streamingStopped() {
|
private void streamingStopped() {
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
@@ -289,14 +308,15 @@ public class Music implements Audio {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
||||||
* aufgerufen, soblad sich auch ein Listener registrieren möchte.
|
* aufgerufen, sobald sich der erste Listener anmelden möchte.
|
||||||
* @return
|
*
|
||||||
|
* @return Der {@code EventDispatcher} für dieses Objekt.
|
||||||
*/
|
*/
|
||||||
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
||||||
if( eventDispatcher == null ) {
|
if( eventDispatcher == null ) {
|
||||||
eventDispatcher = new EventDispatcher<>();
|
eventDispatcher = new EventDispatcher<>();
|
||||||
eventDispatcher.registerEventType("start", (a,l) -> l.playbackStarted(a));
|
eventDispatcher.registerEventType("start", ( a, l ) -> l.playbackStarted(a));
|
||||||
eventDispatcher.registerEventType("stop", (a,l) -> l.playbackStopped(a));
|
eventDispatcher.registerEventType("stop", ( a, l ) -> l.playbackStopped(a));
|
||||||
}
|
}
|
||||||
return eventDispatcher;
|
return eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,80 +10,87 @@ import java.io.IOException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wiedergabe kurzer Soundclips, die mehrmals wiederverwendet werden.
|
* Ein kurzer Soundclip, der mehrmals wiederverwendet werden kann.
|
||||||
* <p>
|
* <p>
|
||||||
* In Spielen und anderen Projekten gibt es oftmals eine Reihe kurzer Sounds,
|
* In Spielen und anderen Projekten gibt es oftmals eine Reihe kurzer
|
||||||
* die zusammen mit bestimmten Aktionen wiedergegeben werden (zum Beispiel, wenn
|
* Soundclips, die zusammen mit bestimmten Aktionen wiedergegeben werden (zum
|
||||||
* die Spielfigur springt, wenn zwei Objekte kollidieren, usw.). Sounds werden
|
* Beispiel, wenn die Spielfigur springt, wenn zwei Objekte kollidieren, usw.).
|
||||||
* komplett in den Speicher geladen und können dadurch immer wieder, als
|
* Sounds werden vollständig in den Speicher geladen und können immer wieder,
|
||||||
* Schleife oder auch nur Abschnittsweise abgespielt werden.
|
* als Schleife oder auch nur Abschnittsweise, abgespielt werden.
|
||||||
* <p>
|
* <p>
|
||||||
* Für längre Musikstücke (beispielsweise Hintergrundmusik) bietet sich eher die
|
* Für längere Musikstücke (beispielsweise Hintergrundmusik) bietet sich eher
|
||||||
* KLasse {@link Music} an.
|
* die Klasse {@link Music} an.
|
||||||
|
*
|
||||||
|
* <h2>MP3-Dateien verwenden</h2>
|
||||||
|
* Java kann nativ nur Waveform ({@code .wav}) Dateien wiedergeben. Um auch
|
||||||
|
* MP3-Dateien zu nutzen, müssen die Bibliotheken <a href="#">jlayer</a>, <a
|
||||||
|
* href="#">tritonus-share</a> und <a href="#">mp3spi</a> eingebunden werden.
|
||||||
|
* Details zur Verwendung können in der <a
|
||||||
|
* href="https://zeichenmaschine.xyz/installation/#unterstutzung-fur-mp3">Dokumentation
|
||||||
|
* der Zeichenmaschine</a> nachgelesen werden.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings( "unused" )
|
@SuppressWarnings( "unused" )
|
||||||
public class Sound implements Audio {
|
public class Sound implements Audio {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ob der Sound gerade abgespielt wird.
|
* Ob der Sound aktuell abgespielt wird.
|
||||||
*/
|
*/
|
||||||
private boolean playing = false;
|
private boolean playing = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ob der Sound gerade in einer Schleife abgespielt wird.
|
* Ob der Sound aktuell in einer Schleife abgespielt wird.
|
||||||
*/
|
*/
|
||||||
private boolean looping = false;
|
private boolean looping = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Quelle des Musikstücks.
|
* Die Quelle der Audiodaten.
|
||||||
*/
|
*/
|
||||||
private String audioSource;
|
private String audioSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Der Clip, falls er schon geladen wurde, sonst {@code null}.
|
* Der Clip, falls er schon geladen wurde. Ansonsten {@code null}.
|
||||||
*/
|
*/
|
||||||
private Clip audioClip;
|
private Clip audioClip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ob die Resourcen des Clips im Speicher nach dem nächsten Abspielen
|
* Ob die Ressourcen des Clips im Speicher nach dem nächsten Abspielen
|
||||||
* freigegeben werden sollen.
|
* freigegeben werden sollen.
|
||||||
*/
|
*/
|
||||||
private boolean disposeAfterPlay = false;
|
private boolean disposeAfterPlay = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Lautstärke des Clips.
|
* Die aktuelle Lautstärke des Clips.
|
||||||
*/
|
*/
|
||||||
private float volume = 0.8f;
|
private float volume = 0.8f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatcher für Audio-Events (start und stop).
|
||||||
|
*/
|
||||||
EventDispatcher<Audio, AudioListener> eventDispatcher;
|
EventDispatcher<Audio, AudioListener> eventDispatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt einen Sound aus der angegebene Quelle.
|
* Erstellt einen Sound aus der angegebene Quelle.
|
||||||
*
|
*
|
||||||
* @param source Ein Dateipfad oder eine Webadresse.
|
* @param source Quelle der Audiodaten.
|
||||||
* @throws NullPointerException Falls die Quelle {@code null} ist.
|
* @throws NullPointerException Falls die Quelle {@code null} ist.
|
||||||
|
* @see ResourceStreamProvider#getResourceURL(String)
|
||||||
*/
|
*/
|
||||||
public Sound( String source ) {
|
public Sound( String source ) {
|
||||||
Validator.requireNotNull(source);
|
Validator.requireNotNull(source);
|
||||||
this.audioSource = source;
|
this.audioSource = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return audioSource;
|
return audioSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPlaying() {
|
public boolean isPlaying() {
|
||||||
// return audioClip != null && audioClip.isRunning();
|
// return audioClip != null && audioClip.isRunning();
|
||||||
return playing;
|
return playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLooping() {
|
public boolean isLooping() {
|
||||||
if( !playing ) {
|
if( !playing ) {
|
||||||
@@ -92,28 +99,21 @@ public class Sound implements Audio {
|
|||||||
return looping;
|
return looping;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setVolume( double volume ) {
|
public void setVolume( double volume ) {
|
||||||
this.volume = (float) volume;
|
this.volume = volume < 0 ? 0f : (float) volume;
|
||||||
if( audioClip != null ) {
|
if( audioClip != null ) {
|
||||||
applyVolume();
|
applyVolume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getVolume() {
|
public double getVolume() {
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, um die gesetzte Lautstärke vor dem Abspielen
|
* Wendet die Lautstärke vor dem Abspielen auf den Clip an.
|
||||||
* anzuwenden.
|
|
||||||
*/
|
*/
|
||||||
private void applyVolume() {
|
private void applyVolume() {
|
||||||
FloatControl gainControl =
|
FloatControl gainControl =
|
||||||
@@ -124,9 +124,6 @@ public class Sound implements Audio {
|
|||||||
gainControl.setValue(vol);
|
gainControl.setValue(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
looping = false;
|
looping = false;
|
||||||
@@ -136,9 +133,6 @@ public class Sound implements Audio {
|
|||||||
playing = false;
|
playing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void play() {
|
public void play() {
|
||||||
if( this.openClip() ) {
|
if( this.openClip() ) {
|
||||||
@@ -147,9 +141,6 @@ public class Sound implements Audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void playAndWait() {
|
public void playAndWait() {
|
||||||
this.play();
|
this.play();
|
||||||
@@ -168,7 +159,7 @@ public class Sound implements Audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spielt den Sound genau einmal ab und gibt danach alle Resourcen des Clips
|
* Spielt den Sound einmal ab und gibt danach alle Ressourcen des Clips
|
||||||
* frei.
|
* frei.
|
||||||
* <p>
|
* <p>
|
||||||
* Der Aufruf ist effektiv gleich zu
|
* Der Aufruf ist effektiv gleich zu
|
||||||
@@ -185,7 +176,7 @@ public class Sound implements Audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spielt den Sound genau einmal ab und gibt danach alle Resourcen des Clips
|
* Spielt den Sound einmal ab und gibt danach alle Ressourcen des Clips
|
||||||
* frei.
|
* frei.
|
||||||
* <p>
|
* <p>
|
||||||
* Der Aufruf entspricht
|
* Der Aufruf entspricht
|
||||||
@@ -199,17 +190,18 @@ public class Sound implements Audio {
|
|||||||
playAndWait();
|
playAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void loop() {
|
public void loop() {
|
||||||
loop(Clip.LOOP_CONTINUOUSLY);
|
loop(Clip.LOOP_CONTINUOUSLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wiederholt den Sound die angegebene Anzahl an Wiederholungen ab und
|
* Wiederholt den Sound die angegebene Anzahl an Wiederholungen und stoppt
|
||||||
* stoppt die Wiedergabe dann.
|
* die Wiedergabe dann.
|
||||||
|
* <p>
|
||||||
|
* Wird {@code count} auf {@link Clip#LOOP_CONTINUOUSLY} gesetzt (-1), wird
|
||||||
|
* der Clip unendlich oft wiederholt. Der Aufruf entspricht dann
|
||||||
|
* {@link #loop()}.
|
||||||
*
|
*
|
||||||
* @param count Anzahl der Wiederholungen.
|
* @param count Anzahl der Wiederholungen.
|
||||||
*/
|
*/
|
||||||
@@ -231,9 +223,6 @@ public class Sound implements Audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void dispose() {
|
public synchronized void dispose() {
|
||||||
if( audioClip != null ) {
|
if( audioClip != null ) {
|
||||||
@@ -245,6 +234,13 @@ public class Sound implements Audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lädt falls nötig den {@link Clip} für die
|
||||||
|
* {@link #audioSource Audioquelle} und startet die Wiedergabe.
|
||||||
|
*
|
||||||
|
* @return {@code true}, wenn der Clip geöffnet werden konnte, {@code false}
|
||||||
|
* sonst.
|
||||||
|
*/
|
||||||
private synchronized boolean openClip() {
|
private synchronized boolean openClip() {
|
||||||
if( audioClip != null ) {
|
if( audioClip != null ) {
|
||||||
audioClip.setFramePosition(0);
|
audioClip.setFramePosition(0);
|
||||||
@@ -307,9 +303,12 @@ public class Sound implements Audio {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, die aufgerufen wird, wenn die Wiedergabe gestoppt wird.
|
* Wird aufgerufen, wenn die Wiedergabe beendet wurde. Entweder durch einen
|
||||||
* Entweder durch einen Aufruf von {@link #stop()} oder, weil die Wiedergabe
|
* Aufruf von {@link #stop()} oder, weil die Wiedergabe nach
|
||||||
* nach {@link #playOnce()} beendet wurde.
|
* {@link #playOnce()} beendet wurde.
|
||||||
|
* <p>
|
||||||
|
* Falls {@link #disposeAfterPlay} gesetzt ist, wird nach dem Ende der
|
||||||
|
* Wiedergabe {@link #dispose()} aufgerufen.
|
||||||
*/
|
*/
|
||||||
private void playbackStopped() {
|
private void playbackStopped() {
|
||||||
playing = false;
|
playing = false;
|
||||||
@@ -332,14 +331,15 @@ public class Sound implements Audio {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
* Interne Methode, um den Listener-Mechanismus zu initialisieren. Wird erst
|
||||||
* aufgerufen, soblad sich auch ein Listener registrieren möchte.
|
* aufgerufen, sobald sich der erste Listener anmelden möchte.
|
||||||
* @return
|
*
|
||||||
|
* @return Der {@code EventDispatcher} für dieses Objekt.
|
||||||
*/
|
*/
|
||||||
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
private EventDispatcher<Audio, AudioListener> initializeEventDispatcher() {
|
||||||
if( eventDispatcher == null ) {
|
if( eventDispatcher == null ) {
|
||||||
eventDispatcher = new EventDispatcher<>();
|
eventDispatcher = new EventDispatcher<>();
|
||||||
eventDispatcher.registerEventType("start", (a,l) -> l.playbackStarted(a));
|
eventDispatcher.registerEventType("start", ( a, l ) -> l.playbackStarted(a));
|
||||||
eventDispatcher.registerEventType("stop", (a,l) -> l.playbackStopped(a));
|
eventDispatcher.registerEventType("stop", ( a, l ) -> l.playbackStopped(a));
|
||||||
}
|
}
|
||||||
return eventDispatcher;
|
return eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,32 +93,20 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
rows * columns);
|
rows * columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int columns() {
|
public int columns() {
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int rows() {
|
public int rows() {
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
int idx( int r, int c ) {
|
int idx( int r, int c ) {
|
||||||
return c * rows + r;
|
return c * rows + r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double get( int row, int col ) {
|
public double get( int row, int col ) {
|
||||||
try {
|
try {
|
||||||
@@ -128,9 +116,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix set( int row, int col, double value ) {
|
public MLMatrix set( int row, int col, double value ) {
|
||||||
try {
|
try {
|
||||||
@@ -141,52 +126,34 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix initializeRandom() {
|
public MLMatrix initializeRandom() {
|
||||||
return initializeRandom(-1.0, 1.0);
|
return initializeRandom(-1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix initializeRandom( double lower, double upper ) {
|
public MLMatrix initializeRandom( double lower, double upper ) {
|
||||||
applyInPlace(( d ) -> ((upper - lower) * Constants.random()) + lower);
|
applyInPlace(( d ) -> ((upper - lower) * Constants.random()) + lower);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix initializeOne() {
|
public MLMatrix initializeOne() {
|
||||||
applyInPlace(( d ) -> 1.0);
|
applyInPlace(( d ) -> 1.0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix initializeZero() {
|
public MLMatrix initializeZero() {
|
||||||
applyInPlace(( d ) -> 0.0);
|
applyInPlace(( d ) -> 0.0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix duplicate() {
|
public MLMatrix duplicate() {
|
||||||
return new DoubleMatrix(this);
|
return new DoubleMatrix(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix multiplyTransposed( MLMatrix B ) {
|
public MLMatrix multiplyTransposed( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -208,9 +175,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix multiplyAddBias( final MLMatrix B, final MLMatrix C ) {
|
public MLMatrix multiplyAddBias( final MLMatrix B, final MLMatrix C ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -233,9 +197,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix transposedMultiplyAndScale( final MLMatrix B, final double scalar ) {
|
public MLMatrix transposedMultiplyAndScale( final MLMatrix B, final double scalar ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, columns).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, columns).parallel().mapToObj(
|
||||||
@@ -258,9 +219,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix add( MLMatrix B ) {
|
public MLMatrix add( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -277,9 +235,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix addInPlace( MLMatrix B ) {
|
public MLMatrix addInPlace( MLMatrix B ) {
|
||||||
for( int j = 0; j < columns; j++ ) {
|
for( int j = 0; j < columns; j++ ) {
|
||||||
@@ -290,9 +245,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix sub( MLMatrix B ) {
|
public MLMatrix sub( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -309,9 +261,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix colSums() {
|
public MLMatrix colSums() {
|
||||||
/*DoubleMatrix colSums = new DoubleMatrix(1, columns);
|
/*DoubleMatrix colSums = new DoubleMatrix(1, columns);
|
||||||
@@ -331,9 +280,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return colSums;
|
return colSums;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix scaleInPlace( final double scalar ) {
|
public MLMatrix scaleInPlace( final double scalar ) {
|
||||||
for( int i = 0; i < coefficients.length; i++ ) {
|
for( int i = 0; i < coefficients.length; i++ ) {
|
||||||
@@ -342,9 +288,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix scaleInPlace( final MLMatrix S ) {
|
public MLMatrix scaleInPlace( final MLMatrix S ) {
|
||||||
for( int j = 0; j < columns; j++ ) {
|
for( int j = 0; j < columns; j++ ) {
|
||||||
@@ -355,9 +298,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix apply( DoubleUnaryOperator op ) {
|
public MLMatrix apply( DoubleUnaryOperator op ) {
|
||||||
DoubleMatrix result = new DoubleMatrix(rows, columns);
|
DoubleMatrix result = new DoubleMatrix(rows, columns);
|
||||||
@@ -367,9 +307,6 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix applyInPlace( DoubleUnaryOperator op ) {
|
public MLMatrix applyInPlace( DoubleUnaryOperator op ) {
|
||||||
for( int i = 0; i < coefficients.length; i++ ) {
|
for( int i = 0; i < coefficients.length; i++ ) {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package schule.ngb.zm.shapes;
|
package schule.ngb.zm.shapes;
|
||||||
|
|
||||||
import schule.ngb.zm.*;
|
import schule.ngb.zm.BasicDrawable;
|
||||||
|
import schule.ngb.zm.Fillable;
|
||||||
|
import schule.ngb.zm.Options;
|
||||||
|
import schule.ngb.zm.Strokeable;
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
@@ -142,9 +145,6 @@ public abstract class Shape extends BasicDrawable {
|
|||||||
*/
|
*/
|
||||||
public abstract double getHeight();
|
public abstract double getHeight();
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to, Options.Direction dir ) {
|
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to, Options.Direction dir ) {
|
||||||
Point2D apDir = getAbsAnchorPoint(dir);
|
Point2D apDir = getAbsAnchorPoint(dir);
|
||||||
@@ -152,9 +152,6 @@ public abstract class Shape extends BasicDrawable {
|
|||||||
setGradient(apInv.getX(), apInv.getY(), from, apDir.getX(), apDir.getY(), to);
|
setGradient(apInv.getX(), apInv.getY(), from, apDir.getX(), apDir.getY(), to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to ) {
|
public void setGradient( schule.ngb.zm.Color from, schule.ngb.zm.Color to ) {
|
||||||
Point2D ap = getAbsAnchorPoint(CENTER);
|
Point2D ap = getAbsAnchorPoint(CENTER);
|
||||||
|
|||||||
@@ -136,57 +136,36 @@ public class BasicChartValue implements ChartValue {
|
|||||||
this.color = color;
|
this.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getX() {
|
public double getX() {
|
||||||
return xValue;
|
return xValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public double getValue() {
|
public double getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue( double pValue ) {
|
public void setValue( double pValue ) {
|
||||||
this.value = pValue;
|
this.value = pValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setLabel( String pLabel ) {
|
public void setLabel( String pLabel ) {
|
||||||
this.label = pLabel;
|
this.label = pLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Color getColor() {
|
public Color getColor() {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setColor( Color pColor ) {
|
public void setColor( Color pColor ) {
|
||||||
this.color = pColor;
|
this.color = pColor;
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package schule.ngb.zm.util;
|
|||||||
|
|
||||||
import schule.ngb.zm.Color;
|
import schule.ngb.zm.Color;
|
||||||
import schule.ngb.zm.Constants;
|
import schule.ngb.zm.Constants;
|
||||||
import schule.ngb.zm.Zeichenmaschine;
|
|
||||||
import schule.ngb.zm.util.io.FileLoader;
|
|
||||||
import schule.ngb.zm.util.io.ImageLoader;
|
import schule.ngb.zm.util.io.ImageLoader;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
@@ -11,46 +9,69 @@ import java.awt.FontMetrics;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.font.LineMetrics;
|
import java.awt.font.LineMetrics;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static java.lang.Math.exp;
|
||||||
|
import static java.lang.Math.log;
|
||||||
|
import static schule.ngb.zm.Constants.random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hilfsklasse, um zufällige Beispieldaten zu erzeugen.
|
* Hilfsklasse, um zufällige Beispieldaten zu erzeugen.
|
||||||
* <p>
|
* <p>
|
||||||
* Die Klasse kann verschiedene Arten realistischer Beispieldaten erzeugen,
|
* Die Klasse kann verschiedene Arten realistischer Beispieldaten erzeugen,
|
||||||
* unter anderem Namen, E-Mail-Adressen, Passwörter oder Platzhalterbilder.
|
* unter anderem Namen, E-Mail-Adressen, Passwörter oder Platzhalter-Bilder.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings( "unused" )
|
||||||
public final class Faker {
|
public final class Faker {
|
||||||
|
|
||||||
public static final String FAKE_IMG_URL = "https://loremflickr.com/%d/%d";
|
public static final String FAKE_IMG_URL = "https://loremflickr.com/%d/%d";
|
||||||
|
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
String text = Faker.fakeText(2000, 8);
|
||||||
|
System.out.println(text);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Nutzernamen.
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Benutzerdaten.
|
||||||
|
* <p>
|
||||||
|
* Jeder Datensatz besteht aus einem String-Array mit den folgenden Daten
|
||||||
|
* <ul>
|
||||||
|
* <li><code>fakeUser[i][0]</code>: Vorname</li>
|
||||||
|
* <li><code>fakeUser[i][1]</code>: Nachname</li>
|
||||||
|
* <li><code>fakeUser[i][2]</code>: Geschlecht</li>
|
||||||
|
* <li><code>fakeUser[i][3]</code>: Nutzername</li>
|
||||||
|
* <li><code>fakeUser[i][4]</code>: Passwort</li>
|
||||||
|
* <li><code>fakeUser[i][5]</code>: E-Mail</li>
|
||||||
|
* <li><code>fakeUser[i][6]</code>: Geburtsdatum</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[][] fakeUsers( int n ) {
|
public static String[][] fakeUsers( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> line.split(","), String[].class);
|
||||||
String[][] result = new String[n][];
|
|
||||||
for( int i = 0; i < n; i++ ) {
|
|
||||||
result[i] = Constants.choice(data);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Vornamen.
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Vornamen.
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[] fakeNames( int n ) {
|
public static String[] fakeNames( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> line.split(",")[0], String.class);
|
||||||
String[] result = new String[n];
|
|
||||||
for( int i = 0; i < n; i++ ) {
|
|
||||||
String[] row = Constants.choice(data);
|
|
||||||
result[i] = row[0];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -58,65 +79,187 @@ public final class Faker {
|
|||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Namen (Vor- und
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Namen (Vor- und
|
||||||
* Nachname).
|
* Nachname).
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[] fakeFullnames( int n ) {
|
public static String[] fakeFullnames( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> {
|
||||||
String[] result = new String[n];
|
String[] parts = line.split(",");
|
||||||
for( int i = 0; i < n; i++ ) {
|
return parts[0] + " " + parts[1];
|
||||||
String[] row = Constants.choice(data);
|
}, String.class);
|
||||||
result[i] = row[0] + " " + row[1];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Nutzernamen.
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Nutzernamen.
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[] fakeUsernames( int n ) {
|
public static String[] fakeUsernames( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> line.split(",")[3], String.class);
|
||||||
String[] result = new String[n];
|
|
||||||
for( int i = 0; i < n; i++ ) {
|
|
||||||
String[] row = Constants.choice(data);
|
|
||||||
result[i] = row[3];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Passwörter.
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger Passwörter.
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[] fakePasswords( int n ) {
|
public static String[] fakePasswords( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> line.split(",")[4], String.class);
|
||||||
String[] result = new String[n];
|
|
||||||
for( int i = 0; i < n; i++ ) {
|
|
||||||
String[] row = Constants.choice(data);
|
|
||||||
result[i] = row[4];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger E-Mail-Adressen.
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger E-Mail-Adressen.
|
||||||
*
|
*
|
||||||
* @param n Anzahl der Beispieldaten.
|
* @param count Anzahl der Beispieldaten.
|
||||||
* @return Ein Array mit den Beispieldaten.
|
* @return Ein Array mit den Beispieldaten.
|
||||||
*/
|
*/
|
||||||
public static String[] fakeEmails( int n ) {
|
public static String[] fakeEmails( int count ) {
|
||||||
String[][] data = loadMockfile("users");
|
return randomSample("users", count, ( line ) -> line.split(",")[5], String.class);
|
||||||
String[] result = new String[n];
|
|
||||||
for( int i = 0; i < n; i++ ) {
|
|
||||||
String[] row = Constants.choice(data);
|
|
||||||
result[i] = row[5];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger deutscher
|
||||||
|
* Wörter.
|
||||||
|
*
|
||||||
|
* @param count Anzahl der Beispieldaten.
|
||||||
|
* @return Ein Array mit den Beispieldaten.
|
||||||
|
*/
|
||||||
|
public static String[] fakeStrings( int count ) {
|
||||||
|
return randomSample("words", count, ( line ) -> line, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt ein Array mit den angegebenen Anzahl zufälliger
|
||||||
|
* {@code Date}-Objekte.
|
||||||
|
*
|
||||||
|
* @param count Anzahl der Beispieldaten.
|
||||||
|
* @return Ein Array mit den Beispieldaten.
|
||||||
|
*/
|
||||||
|
public static LocalDate[] fakeDates( int count ) {
|
||||||
|
long nowEpoch = LocalDate.now().toEpochDay();
|
||||||
|
long from = LocalDate.ofEpochDay(nowEpoch - 18 * 365).toEpochDay();
|
||||||
|
long to = LocalDate.ofEpochDay(nowEpoch - 14 * 365).toEpochDay();
|
||||||
|
|
||||||
|
LocalDate[] result = new LocalDate[count];
|
||||||
|
for( int i = 0; i < count; i++ ) {
|
||||||
|
result[i] = LocalDate.ofEpochDay((int) Constants.interpolate(from, to, random()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime[] fakeDatetimes( int count ) {
|
||||||
|
long nowEpoch = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
|
||||||
|
long from = LocalDateTime.ofEpochSecond(nowEpoch - 18 * 365, 0, ZoneOffset.UTC).toEpochSecond(ZoneOffset.UTC);
|
||||||
|
long to = LocalDateTime.ofEpochSecond(nowEpoch - 14 * 365, 0, ZoneOffset.UTC).toEpochSecond(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
LocalDateTime[] result = new LocalDateTime[count];
|
||||||
|
for( int i = 0; i < count; i++ ) {
|
||||||
|
result[i] = LocalDateTime.ofEpochSecond((int) Constants.interpolate(from, to, random()), 0, ZoneOffset.UTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fakeText( int words, int paragraphs ) {
|
||||||
|
String basetext = "";
|
||||||
|
try(
|
||||||
|
InputStream in = Faker.class.getResourceAsStream("mock-text.txt");
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in))
|
||||||
|
) {
|
||||||
|
basetext = reader.readLine();
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
LOG.error(ex, "Error generating fake blindtext: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = basetext.repeat(words / 283);
|
||||||
|
|
||||||
|
int w = (words % 283);
|
||||||
|
if( w > 0 ) {
|
||||||
|
Matcher m = Pattern.compile("([a-zA-Z_0-9\\u00C0-\\u017F]+\\W+){" + w + "}").matcher(basetext);
|
||||||
|
if( m.find() ) {
|
||||||
|
result += m.group().stripTrailing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( paragraphs > 1 ) {
|
||||||
|
int half = words / paragraphs;
|
||||||
|
final int maxLength = result.length();
|
||||||
|
Matcher m = Pattern.compile("([a-zA-Z_0-9\\u00C0-\\u017F]+\\W+){" + (half - 10) + "," + (half + 10) + "}([a-zA-Z_0-9\\u00C0-\\u017F]+)\\.").matcher(result);
|
||||||
|
if( m.find() ) {
|
||||||
|
result = m.replaceAll(( mr ) -> mr.end() == maxLength ? mr.group().trim() : mr.group().trim() + "\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] fakeIntArray( int count, int min, int max ) {
|
||||||
|
int[] arr = new int[count];
|
||||||
|
for( int i = 0; i < count; i++ ) {
|
||||||
|
arr[i] = random(min, max);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Integer> fakeIntegerList( int count, int min, int max, List<Integer> list ) {
|
||||||
|
if( list == null ) {
|
||||||
|
list = new ArrayList<>(count);
|
||||||
|
}
|
||||||
|
for( int i = 0; i < count; i++ ) {
|
||||||
|
list.add(random(min, max));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
private static <T> T[] randomSample( String filename, int count, Function<String, T> transformer, Class<T> type ) {
|
||||||
|
T[] result = (T[]) Array.newInstance(type, count);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
double k = count; // cast to double
|
||||||
|
|
||||||
|
double W = exp(log(random()) / k);
|
||||||
|
|
||||||
|
try(
|
||||||
|
InputStream in = Faker.class.getResourceAsStream("mock-" + filename + ".csv");
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in))
|
||||||
|
) {
|
||||||
|
String line;
|
||||||
|
while( (line = reader.readLine()) != null ) {
|
||||||
|
if( i < count ) {
|
||||||
|
result[i] = transformer.apply(line);
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
int j = (int) (log(random()) / log(1 - W)) + 1;
|
||||||
|
while( j > 0 ) {
|
||||||
|
line = reader.readLine();
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( line != null ) {
|
||||||
|
result[random(0, count - 1)] = transformer.apply(line);
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
W *= exp(log(random()) / k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill remaining array
|
||||||
|
while( i < count ) {
|
||||||
|
result[i] = result[random(0, i - 1)];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
LOG.error(ex, "Error loading mock data file: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +308,7 @@ public final class Faker {
|
|||||||
FontMetrics fontMerics = graphics.getFontMetrics();
|
FontMetrics fontMerics = graphics.getFontMetrics();
|
||||||
LineMetrics lineMetrics = fontMerics.getLineMetrics(text, graphics);
|
LineMetrics lineMetrics = fontMerics.getLineMetrics(text, graphics);
|
||||||
graphics.drawString(text,
|
graphics.drawString(text,
|
||||||
(int) ((width - fontMerics.stringWidth(text)) / 2),
|
(width - fontMerics.stringWidth(text)) / 2,
|
||||||
(int) (height / 2 - lineMetrics.getDescent() + lineMetrics.getAscent() / 2)
|
(int) (height / 2 - lineMetrics.getDescent() + lineMetrics.getAscent() / 2)
|
||||||
);
|
);
|
||||||
graphics.dispose();
|
graphics.dispose();
|
||||||
@@ -176,15 +319,9 @@ public final class Faker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String fakeText( int words, int paragraphs ) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[][] loadMockfile( String name ) {
|
|
||||||
return FileLoader.loadCsv("schule/ngb/zm/util/mock-" + name + ".csv", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Faker() {
|
private Faker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Log LOG = Log.getLogger(Faker.class);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,60 @@ import java.util.concurrent.ConcurrentMap;
|
|||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementierung einer EventListener-API basierend auf dem Artikel
|
||||||
|
* <a href="https://org.coloradomesa.edu/~wmacevoy/listen/paper.html">Skilled
|
||||||
|
* Listening in Java</a> von Dr. Warren D. MacEvoy.
|
||||||
|
* <p>
|
||||||
|
* Der {@code EventDispatcher} verwaltet eine Liste von angemeldeten Listenern
|
||||||
|
* in einem {@link CopyOnWriteArraySet}, dass besonders für Situationen geeignet
|
||||||
|
* ist, in denen in der Regel wenige Objekte verwaltet werden müssen, auf die
|
||||||
|
* schnell zugegriffen werden soll und die sich selten ändern. Das trifft in den
|
||||||
|
* meisten Fällen auf die Listener eines Objekts zu.
|
||||||
|
* <p>
|
||||||
|
* Um einen {@code EventDispatcher} zu nutzen, muss eine Schnittstelle als
|
||||||
|
* Unterinterface von {@link Listener} erstellt werden, die Methoden für die
|
||||||
|
* einzelnen Events definiert. In der Regel wird eine Methode pro Event
|
||||||
|
* angelegt, aber dies ist nicht unbedingt notwendig.
|
||||||
|
* <p>
|
||||||
|
* Ein Objekt, dass Events für diese Art von Listener erzeugt, erstellt einen
|
||||||
|
* {@code EventDispatcher} und
|
||||||
|
* {@link #registerEventType(String, BiConsumer) registriert} die notwendigen
|
||||||
|
* Events.
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* EventDispatcher<MyEvent, MyEventListener> dispatcher = new EventDispatcher<>();
|
||||||
|
* dispatcher.registerEventType("start", (evt, listener) -> listener.started(evt));
|
||||||
|
* dispatcher.registerEventType("stop", (evt, listener) -> listener.stopped(evt));
|
||||||
|
* </code></pre>
|
||||||
|
* <p>
|
||||||
|
* Hier werden zwei Events registriert "start" und "stop". Die Bezeichnung der
|
||||||
|
* Events wird nut intern verwendet. Jedes Event registriert eine Funktion, die
|
||||||
|
* den Aufruf der Listener-Schnittstelle umsetzt. In der Regel ist dies ein
|
||||||
|
* Lambda-Ausdruck von zwei Parametern: dem Event-Objekt vom Typ {@code E} und
|
||||||
|
* der Listener, der aufgerufen werden soll, vom Typ {@code L}.
|
||||||
|
* <p>
|
||||||
|
* Nun können {@code MyEventListener} angemeldet und Events ausgelöst werden.
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* public void addEventListener( MyEventListener listener ) {
|
||||||
|
* dispatcher.addListener(listener);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public void removeEventListener( MyEventListener listener ) {
|
||||||
|
* dispatcher.removeListener(listener);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public void methodThatCreatesEvents() {
|
||||||
|
* dispatcher.dispatchEvent("start", new MyEvent());
|
||||||
|
* // Do something
|
||||||
|
* dispatcher.dispatchEvent("stop", new MyEvent());
|
||||||
|
* }
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* @param <E> Typ der Event-Objekte.
|
||||||
|
* @param <L> Typ der verwendeten Listener-Schnittstelle.
|
||||||
|
*/
|
||||||
public class EventDispatcher<E, L extends Listener<E>> {
|
public class EventDispatcher<E, L extends Listener<E>> {
|
||||||
|
|
||||||
private final CopyOnWriteArraySet<L> listeners;
|
private final CopyOnWriteArraySet<L> listeners;
|
||||||
@@ -35,6 +89,7 @@ public class EventDispatcher<E, L extends Listener<E>> {
|
|||||||
listeners.remove(listener);
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public boolean hasListeners() {
|
public boolean hasListeners() {
|
||||||
return !listeners.isEmpty();
|
return !listeners.isEmpty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
package schule.ngb.zm.util.events;
|
package schule.ngb.zm.util.events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generische Basisschnittstelle für die Implementierung von EventListenern.
|
||||||
|
*
|
||||||
|
* @param <E> Typ der Event-Objekte, die von diesem Listener empfangen werden.
|
||||||
|
* @see EventDispatcher
|
||||||
|
*/
|
||||||
public interface Listener<E> {
|
public interface Listener<E> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/main/resources/schule/ngb/zm/util/mock-text.txt
Normal file
1
src/main/resources/schule/ngb/zm/util/mock-text.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Weit hinten, hinter den Wortbergen, fern der Länder Vokalien und Konsonantien leben die Blindtexte. Abgeschieden wohnen Sie in Buchstabhausen an der Küste des Semantik, eines großen Sprachozeans. Ein kleines Bächlein namens Duden fließt durch ihren Ort und versorgt sie mit den nötigen Regelialien. Es ist ein paradiesmatisches Land, in dem einem gebratene Satzteile in den Mund fliegen. Nicht einmal von der allmächtigen Interpunktion werden die Blindtexte beherrscht - ein geradezu unorthographisches Leben. Eines Tages aber beschloß eine kleine Zeile Blindtext, ihr Name war Lorem Ipsum, hinaus zu gehen in die weite Grammatik. Der große Oxmox riet ihr davon ab, da es dort wimmele von bösen Kommata, wilden Fragezeichen und hinterhältigen Semikoli, doch das Blindtextchen ließ sich nicht beirren. Es packte seine sieben Versalien, schob sich sein Initial in den Gürtel und machte sich auf den Weg. Als es die ersten Hügel des Kursivgebirges erklommen hatte, warf es einen letzten Blick zurück auf die Skyline seiner Heimatstadt Buchstabhausen, die Headline von Alphabetdorf und die Subline seiner eigenen Straße, der Zeilengasse. Wehmütig lief ihm eine rethorische Frage über die Wange, dann setzte es seinen Weg fort. Unterwegs traf es eine Copy. Die Copy warnte das Blindtextchen, da, wo sie herkäme wäre sie zigmal umgeschrieben worden und alles, was von ihrem Ursprung noch übrig wäre, sei das Wort "und" und das Blindtextchen solle umkehren und wieder in sein eigenes, sicheres Land zurückkehren. Doch alles Gutzureden konnte es nicht überzeugen und so dauerte es nicht lange, bis ihm ein paar heimtückische Werbetexter auflauerten, es mit Longe und Parole betrunken machten und es dann in ihre Agentur schleppten, wo sie es für ihre Projekte wieder und wieder mißbrauchten. Und wenn es nicht umgeschrieben wurde, dann benutzen Sie es immernoch.
|
||||||
File diff suppressed because it is too large
Load Diff
949
src/main/resources/schule/ngb/zm/util/mock-words.csv
Normal file
949
src/main/resources/schule/ngb/zm/util/mock-words.csv
Normal file
@@ -0,0 +1,949 @@
|
|||||||
|
Abbau
|
||||||
|
Abend
|
||||||
|
Abzug
|
||||||
|
Adler
|
||||||
|
Adolf
|
||||||
|
Agent
|
||||||
|
Akten
|
||||||
|
Aktie
|
||||||
|
Alarm
|
||||||
|
Album
|
||||||
|
Allee
|
||||||
|
Alpen
|
||||||
|
Ampel
|
||||||
|
Amtes
|
||||||
|
Anbau
|
||||||
|
Angst
|
||||||
|
Anruf
|
||||||
|
Anton
|
||||||
|
Anzug
|
||||||
|
Apple
|
||||||
|
April
|
||||||
|
Areal
|
||||||
|
Arena
|
||||||
|
Armee
|
||||||
|
Armut
|
||||||
|
Arten
|
||||||
|
Asien
|
||||||
|
Athen
|
||||||
|
Augen
|
||||||
|
Autor
|
||||||
|
Autos
|
||||||
|
Baden
|
||||||
|
Bande
|
||||||
|
Bands
|
||||||
|
Basel
|
||||||
|
Basis
|
||||||
|
Bauch
|
||||||
|
Bauer
|
||||||
|
Bayer
|
||||||
|
Beate
|
||||||
|
Beide
|
||||||
|
Beine
|
||||||
|
Beleg
|
||||||
|
Bernd
|
||||||
|
Beruf
|
||||||
|
Beste
|
||||||
|
Beton
|
||||||
|
Beute
|
||||||
|
Bevor
|
||||||
|
Bezug
|
||||||
|
Bibel
|
||||||
|
Bitte
|
||||||
|
Blatt
|
||||||
|
Blick
|
||||||
|
Block
|
||||||
|
Blues
|
||||||
|
Bogen
|
||||||
|
Bombe
|
||||||
|
Boris
|
||||||
|
Brand
|
||||||
|
Braun
|
||||||
|
Brief
|
||||||
|
Bruch
|
||||||
|
Bruno
|
||||||
|
Brust
|
||||||
|
Buben
|
||||||
|
Buche
|
||||||
|
Busse
|
||||||
|
Bäume
|
||||||
|
Böden
|
||||||
|
Börse
|
||||||
|
Bühne
|
||||||
|
Büros
|
||||||
|
Chaos
|
||||||
|
Chefs
|
||||||
|
Chile
|
||||||
|
China
|
||||||
|
Clubs
|
||||||
|
Coach
|
||||||
|
Daher
|
||||||
|
Damen
|
||||||
|
Daran
|
||||||
|
Darum
|
||||||
|
Datei
|
||||||
|
Daten
|
||||||
|
Datum
|
||||||
|
Dauer
|
||||||
|
David
|
||||||
|
Davon
|
||||||
|
Decke
|
||||||
|
Deren
|
||||||
|
Diana
|
||||||
|
Dinge
|
||||||
|
Donau
|
||||||
|
Doris
|
||||||
|
Drama
|
||||||
|
Dreck
|
||||||
|
Druck
|
||||||
|
Duell
|
||||||
|
Durch
|
||||||
|
Ecken
|
||||||
|
Edith
|
||||||
|
Eiern
|
||||||
|
Eisen
|
||||||
|
Elite
|
||||||
|
Engel
|
||||||
|
Enkel
|
||||||
|
Erbin
|
||||||
|
Erich
|
||||||
|
Erika
|
||||||
|
Erlös
|
||||||
|
Ernst
|
||||||
|
Erste
|
||||||
|
Erwin
|
||||||
|
Essen
|
||||||
|
Ethik
|
||||||
|
Fahne
|
||||||
|
Fahrt
|
||||||
|
Falls
|
||||||
|
Farbe
|
||||||
|
Faust
|
||||||
|
Fazit
|
||||||
|
Feier
|
||||||
|
Feind
|
||||||
|
Felix
|
||||||
|
Ferne
|
||||||
|
Feuer
|
||||||
|
Figur
|
||||||
|
Filme
|
||||||
|
Films
|
||||||
|
Firma
|
||||||
|
Fisch
|
||||||
|
Flüge
|
||||||
|
Focus
|
||||||
|
Folge
|
||||||
|
Fonds
|
||||||
|
Forum
|
||||||
|
Fotos
|
||||||
|
Foyer
|
||||||
|
Franc
|
||||||
|
Frank
|
||||||
|
Franz
|
||||||
|
Frist
|
||||||
|
Fritz
|
||||||
|
Front
|
||||||
|
Frust
|
||||||
|
Fuchs
|
||||||
|
Fulda
|
||||||
|
Fälle
|
||||||
|
Fülle
|
||||||
|
Füßen
|
||||||
|
Geben
|
||||||
|
Gebot
|
||||||
|
Gehen
|
||||||
|
Gehör
|
||||||
|
Geist
|
||||||
|
Georg
|
||||||
|
Gerda
|
||||||
|
Gerät
|
||||||
|
Geste
|
||||||
|
Glanz
|
||||||
|
Glück
|
||||||
|
Gnade
|
||||||
|
Gramm
|
||||||
|
Griff
|
||||||
|
Group
|
||||||
|
Grund
|
||||||
|
Grüne
|
||||||
|
Gunst
|
||||||
|
Gutes
|
||||||
|
Gäste
|
||||||
|
Güter
|
||||||
|
Haare
|
||||||
|
Haars
|
||||||
|
Hafen
|
||||||
|
Halle
|
||||||
|
Hanau
|
||||||
|
Handy
|
||||||
|
Harry
|
||||||
|
Hauch
|
||||||
|
Hause
|
||||||
|
Hebel
|
||||||
|
Heike
|
||||||
|
Heims
|
||||||
|
Heinz
|
||||||
|
Helga
|
||||||
|
Henry
|
||||||
|
Herrn
|
||||||
|
Hilfe
|
||||||
|
Hitze
|
||||||
|
Horst
|
||||||
|
Hosen
|
||||||
|
Hotel
|
||||||
|
Huber
|
||||||
|
Humor
|
||||||
|
Hunde
|
||||||
|
Hände
|
||||||
|
Härte
|
||||||
|
Hätte
|
||||||
|
Höhen
|
||||||
|
Hölle
|
||||||
|
Hörer
|
||||||
|
Hügel
|
||||||
|
Hürde
|
||||||
|
Hütte
|
||||||
|
Ideen
|
||||||
|
Image
|
||||||
|
Index
|
||||||
|
Indiz
|
||||||
|
Infos
|
||||||
|
Insel
|
||||||
|
Intel
|
||||||
|
Irene
|
||||||
|
Islam
|
||||||
|
Jahre
|
||||||
|
Jakob
|
||||||
|
James
|
||||||
|
Japan
|
||||||
|
Jeans
|
||||||
|
Jesus
|
||||||
|
Josef
|
||||||
|
Jubel
|
||||||
|
Juden
|
||||||
|
Julia
|
||||||
|
Jungs
|
||||||
|
Jutta
|
||||||
|
Jäger
|
||||||
|
Kabel
|
||||||
|
Kabul
|
||||||
|
Kader
|
||||||
|
Kairo
|
||||||
|
Kampf
|
||||||
|
Kanal
|
||||||
|
Karin
|
||||||
|
Karte
|
||||||
|
Kasse
|
||||||
|
Kenia
|
||||||
|
Kette
|
||||||
|
Kinos
|
||||||
|
Kirch
|
||||||
|
Klage
|
||||||
|
Klaus
|
||||||
|
Klima
|
||||||
|
Klubs
|
||||||
|
Kohle
|
||||||
|
Kohls
|
||||||
|
Konto
|
||||||
|
Kopie
|
||||||
|
Korea
|
||||||
|
Kraft
|
||||||
|
Krebs
|
||||||
|
Kreis
|
||||||
|
Kreml
|
||||||
|
Kreuz
|
||||||
|
Krieg
|
||||||
|
Kripo
|
||||||
|
Krise
|
||||||
|
Krone
|
||||||
|
Krupp
|
||||||
|
Kugel
|
||||||
|
Kunde
|
||||||
|
Kunst
|
||||||
|
Kurse
|
||||||
|
Kurve
|
||||||
|
König
|
||||||
|
Köpfe
|
||||||
|
Küche
|
||||||
|
Kürze
|
||||||
|
Küste
|
||||||
|
Labor
|
||||||
|
Lager
|
||||||
|
Laien
|
||||||
|
Lande
|
||||||
|
Lange
|
||||||
|
Laufe
|
||||||
|
Laune
|
||||||
|
Leder
|
||||||
|
Legen
|
||||||
|
Lehre
|
||||||
|
Leser
|
||||||
|
Leute
|
||||||
|
Licht
|
||||||
|
Linie
|
||||||
|
Linke
|
||||||
|
Liste
|
||||||
|
Liter
|
||||||
|
Logik
|
||||||
|
Lokal
|
||||||
|
Luxus
|
||||||
|
Lyrik
|
||||||
|
Löhne
|
||||||
|
Löwen
|
||||||
|
Lücke
|
||||||
|
Macht
|
||||||
|
Mafia
|
||||||
|
Magen
|
||||||
|
Mainz
|
||||||
|
Major
|
||||||
|
Maler
|
||||||
|
Maria
|
||||||
|
Marie
|
||||||
|
Mario
|
||||||
|
Marke
|
||||||
|
Markt
|
||||||
|
Maske
|
||||||
|
Masse
|
||||||
|
Match
|
||||||
|
Mauer
|
||||||
|
Media
|
||||||
|
Meist
|
||||||
|
Menge
|
||||||
|
Meter
|
||||||
|
Metro
|
||||||
|
Meyer
|
||||||
|
Miami
|
||||||
|
Milch
|
||||||
|
Minen
|
||||||
|
Mitte
|
||||||
|
Monat
|
||||||
|
Moral
|
||||||
|
Motiv
|
||||||
|
Motor
|
||||||
|
Motto
|
||||||
|
Musik
|
||||||
|
Möbel
|
||||||
|
Nacht
|
||||||
|
Nagel
|
||||||
|
Namen
|
||||||
|
Natur
|
||||||
|
Nazis
|
||||||
|
Nebel
|
||||||
|
Netze
|
||||||
|
Noten
|
||||||
|
Ohren
|
||||||
|
Onkel
|
||||||
|
Opfer
|
||||||
|
Orden
|
||||||
|
Organ
|
||||||
|
Orten
|
||||||
|
Oskar
|
||||||
|
Osten
|
||||||
|
Paare
|
||||||
|
Paket
|
||||||
|
Panik
|
||||||
|
Papst
|
||||||
|
Paris
|
||||||
|
Parks
|
||||||
|
Party
|
||||||
|
Pause
|
||||||
|
Pence
|
||||||
|
Peter
|
||||||
|
Petra
|
||||||
|
Pferd
|
||||||
|
Pfund
|
||||||
|
Phase
|
||||||
|
Pilot
|
||||||
|
Platz
|
||||||
|
Polen
|
||||||
|
Preis
|
||||||
|
Prinz
|
||||||
|
Probe
|
||||||
|
Profi
|
||||||
|
Prosa
|
||||||
|
Punkt
|
||||||
|
Quote
|
||||||
|
Rache
|
||||||
|
Radio
|
||||||
|
Rande
|
||||||
|
Rasen
|
||||||
|
Ratte
|
||||||
|
Rauch
|
||||||
|
Regel
|
||||||
|
Regen
|
||||||
|
Regie
|
||||||
|
Reihe
|
||||||
|
Rente
|
||||||
|
Reste
|
||||||
|
Rhein
|
||||||
|
Rolle
|
||||||
|
Roman
|
||||||
|
Route
|
||||||
|
Rover
|
||||||
|
Rubel
|
||||||
|
Russe
|
||||||
|
Räder
|
||||||
|
Römer
|
||||||
|
Sache
|
||||||
|
Sauna
|
||||||
|
Schau
|
||||||
|
Schoß
|
||||||
|
Seele
|
||||||
|
Segen
|
||||||
|
Seite
|
||||||
|
Sekte
|
||||||
|
Senat
|
||||||
|
Seoul
|
||||||
|
Serie
|
||||||
|
Shell
|
||||||
|
Sicht
|
||||||
|
Simon
|
||||||
|
Sinne
|
||||||
|
Smith
|
||||||
|
Songs
|
||||||
|
Sonne
|
||||||
|
Sound
|
||||||
|
Spiel
|
||||||
|
Sport
|
||||||
|
Spree
|
||||||
|
Staat
|
||||||
|
Stadt
|
||||||
|
Stamm
|
||||||
|
Stars
|
||||||
|
Start
|
||||||
|
Stasi
|
||||||
|
Staub
|
||||||
|
Staus
|
||||||
|
Stein
|
||||||
|
Stern
|
||||||
|
Stirn
|
||||||
|
Stock
|
||||||
|
Stoff
|
||||||
|
Story
|
||||||
|
Strom
|
||||||
|
Stufe
|
||||||
|
Stuhl
|
||||||
|
Sturm
|
||||||
|
Sturz
|
||||||
|
Stück
|
||||||
|
Summe
|
||||||
|
Szene
|
||||||
|
Sätze
|
||||||
|
Söhne
|
||||||
|
Süden
|
||||||
|
Tagen
|
||||||
|
Tages
|
||||||
|
Tante
|
||||||
|
Tarif
|
||||||
|
Teams
|
||||||
|
Tempo
|
||||||
|
Tenor
|
||||||
|
Tests
|
||||||
|
Texas
|
||||||
|
Texte
|
||||||
|
Thema
|
||||||
|
These
|
||||||
|
Thron
|
||||||
|
Tiefs
|
||||||
|
Tiere
|
||||||
|
Tiger
|
||||||
|
Tisch
|
||||||
|
Titel
|
||||||
|
Todes
|
||||||
|
Tokio
|
||||||
|
Tonne
|
||||||
|
Toren
|
||||||
|
Traum
|
||||||
|
Treff
|
||||||
|
Trend
|
||||||
|
Trick
|
||||||
|
Trios
|
||||||
|
Trost
|
||||||
|
Typen
|
||||||
|
Täter
|
||||||
|
Tönen
|
||||||
|
Türen
|
||||||
|
Türke
|
||||||
|
UdSSR
|
||||||
|
Uhren
|
||||||
|
Ulmer
|
||||||
|
Umbau
|
||||||
|
Umzug
|
||||||
|
Union
|
||||||
|
Unmut
|
||||||
|
Vater
|
||||||
|
Vetos
|
||||||
|
Video
|
||||||
|
Villa
|
||||||
|
Viren
|
||||||
|
Virus
|
||||||
|
Vogts
|
||||||
|
Votum
|
||||||
|
Vögel
|
||||||
|
Waffe
|
||||||
|
Weber
|
||||||
|
Weile
|
||||||
|
Welle
|
||||||
|
Werke
|
||||||
|
Werks
|
||||||
|
Wesen
|
||||||
|
Wiese
|
||||||
|
Wille
|
||||||
|
Willi
|
||||||
|
Wirte
|
||||||
|
Wirts
|
||||||
|
Witwe
|
||||||
|
Witze
|
||||||
|
Woche
|
||||||
|
Wolke
|
||||||
|
World
|
||||||
|
Worte
|
||||||
|
Wände
|
||||||
|
Wüste
|
||||||
|
Zaire
|
||||||
|
Zeile
|
||||||
|
Zelle
|
||||||
|
Zeugs
|
||||||
|
Ziels
|
||||||
|
Zitat
|
||||||
|
Zorns
|
||||||
|
Zunge
|
||||||
|
Zweck
|
||||||
|
Zähne
|
||||||
|
Zügen
|
||||||
|
ahnen
|
||||||
|
ahnst
|
||||||
|
aktiv
|
||||||
|
allem
|
||||||
|
allen
|
||||||
|
aller
|
||||||
|
alles
|
||||||
|
allzu
|
||||||
|
altem
|
||||||
|
alten
|
||||||
|
altes
|
||||||
|
angab
|
||||||
|
armen
|
||||||
|
außen
|
||||||
|
außer
|
||||||
|
bauen
|
||||||
|
baute
|
||||||
|
bekam
|
||||||
|
berge
|
||||||
|
berät
|
||||||
|
besaß
|
||||||
|
bezog
|
||||||
|
biete
|
||||||
|
birgt
|
||||||
|
blaue
|
||||||
|
blieb
|
||||||
|
blind
|
||||||
|
bloße
|
||||||
|
boten
|
||||||
|
brach
|
||||||
|
breit
|
||||||
|
bunte
|
||||||
|
bösen
|
||||||
|
dabei
|
||||||
|
dafür
|
||||||
|
dahin
|
||||||
|
damit
|
||||||
|
darin
|
||||||
|
davor
|
||||||
|
deine
|
||||||
|
denen
|
||||||
|
denke
|
||||||
|
denkt
|
||||||
|
derer
|
||||||
|
desto
|
||||||
|
dicht
|
||||||
|
dicke
|
||||||
|
dient
|
||||||
|
diese
|
||||||
|
drauf
|
||||||
|
dreht
|
||||||
|
drohe
|
||||||
|
droht
|
||||||
|
dürfe
|
||||||
|
ebene
|
||||||
|
echte
|
||||||
|
ehren
|
||||||
|
eigen
|
||||||
|
einem
|
||||||
|
einen
|
||||||
|
einer
|
||||||
|
eines
|
||||||
|
einig
|
||||||
|
einst
|
||||||
|
eisig
|
||||||
|
elend
|
||||||
|
enden
|
||||||
|
endet
|
||||||
|
engem
|
||||||
|
engen
|
||||||
|
enger
|
||||||
|
enges
|
||||||
|
enorm
|
||||||
|
erben
|
||||||
|
ergab
|
||||||
|
erhob
|
||||||
|
ernte
|
||||||
|
etwas
|
||||||
|
ewige
|
||||||
|
exakt
|
||||||
|
extra
|
||||||
|
fehle
|
||||||
|
fehlt
|
||||||
|
feine
|
||||||
|
feste
|
||||||
|
finde
|
||||||
|
folgt
|
||||||
|
frage
|
||||||
|
fragt
|
||||||
|
freie
|
||||||
|
fremd
|
||||||
|
freut
|
||||||
|
frühe
|
||||||
|
fähig
|
||||||
|
fällt
|
||||||
|
fängt
|
||||||
|
fügte
|
||||||
|
fühle
|
||||||
|
fühlt
|
||||||
|
führe
|
||||||
|
führt
|
||||||
|
füllt
|
||||||
|
gaben
|
||||||
|
ganze
|
||||||
|
gegen
|
||||||
|
gelbe
|
||||||
|
gelte
|
||||||
|
gemäß
|
||||||
|
genau
|
||||||
|
genug
|
||||||
|
gerne
|
||||||
|
getan
|
||||||
|
geübt
|
||||||
|
ginge
|
||||||
|
gingt
|
||||||
|
glatt
|
||||||
|
graue
|
||||||
|
große
|
||||||
|
gutem
|
||||||
|
guten
|
||||||
|
haben
|
||||||
|
halbe
|
||||||
|
halte
|
||||||
|
heben
|
||||||
|
hebst
|
||||||
|
hefte
|
||||||
|
heiße
|
||||||
|
heißt
|
||||||
|
helle
|
||||||
|
heran
|
||||||
|
herum
|
||||||
|
heuer
|
||||||
|
heute
|
||||||
|
hielt
|
||||||
|
hilft
|
||||||
|
hinzu
|
||||||
|
hoffe
|
||||||
|
hofft
|
||||||
|
hohem
|
||||||
|
hohes
|
||||||
|
holen
|
||||||
|
holte
|
||||||
|
hängt
|
||||||
|
höher
|
||||||
|
hören
|
||||||
|
hörte
|
||||||
|
ideal
|
||||||
|
ihnen
|
||||||
|
ihrem
|
||||||
|
ihren
|
||||||
|
ihrer
|
||||||
|
ihres
|
||||||
|
immer
|
||||||
|
indem
|
||||||
|
indes
|
||||||
|
innen
|
||||||
|
jedem
|
||||||
|
jeden
|
||||||
|
jeder
|
||||||
|
jedes
|
||||||
|
jeher
|
||||||
|
jenem
|
||||||
|
jenen
|
||||||
|
jener
|
||||||
|
jenes
|
||||||
|
jetzt
|
||||||
|
junge
|
||||||
|
kalte
|
||||||
|
kauft
|
||||||
|
kehrt
|
||||||
|
keine
|
||||||
|
kenne
|
||||||
|
kennt
|
||||||
|
klagt
|
||||||
|
klang
|
||||||
|
klare
|
||||||
|
klein
|
||||||
|
knapp
|
||||||
|
komme
|
||||||
|
kommt
|
||||||
|
krank
|
||||||
|
kämen
|
||||||
|
könne
|
||||||
|
lacht
|
||||||
|
laden
|
||||||
|
lagen
|
||||||
|
lasse
|
||||||
|
leben
|
||||||
|
lebte
|
||||||
|
leere
|
||||||
|
legte
|
||||||
|
lehnt
|
||||||
|
lehrt
|
||||||
|
leise
|
||||||
|
lernt
|
||||||
|
lesen
|
||||||
|
liebe
|
||||||
|
liebt
|
||||||
|
liege
|
||||||
|
liegt
|
||||||
|
liest
|
||||||
|
ließe
|
||||||
|
links
|
||||||
|
lobte
|
||||||
|
lockt
|
||||||
|
lohnt
|
||||||
|
lässt
|
||||||
|
läuft
|
||||||
|
lösen
|
||||||
|
löste
|
||||||
|
mache
|
||||||
|
manch
|
||||||
|
meine
|
||||||
|
meint
|
||||||
|
merkt
|
||||||
|
messe
|
||||||
|
miete
|
||||||
|
minus
|
||||||
|
morde
|
||||||
|
mögen
|
||||||
|
müsse
|
||||||
|
nahen
|
||||||
|
neben
|
||||||
|
nebst
|
||||||
|
nehme
|
||||||
|
nennt
|
||||||
|
nette
|
||||||
|
neuem
|
||||||
|
neuen
|
||||||
|
neuer
|
||||||
|
neues
|
||||||
|
nicht
|
||||||
|
nimmt
|
||||||
|
näher
|
||||||
|
nötig
|
||||||
|
nützt
|
||||||
|
obere
|
||||||
|
offen
|
||||||
|
ordne
|
||||||
|
packe
|
||||||
|
packt
|
||||||
|
parat
|
||||||
|
passe
|
||||||
|
passt
|
||||||
|
plane
|
||||||
|
plant
|
||||||
|
prüfe
|
||||||
|
prüft
|
||||||
|
quasi
|
||||||
|
rasch
|
||||||
|
raten
|
||||||
|
reale
|
||||||
|
recht
|
||||||
|
reden
|
||||||
|
redet
|
||||||
|
reich
|
||||||
|
reine
|
||||||
|
reise
|
||||||
|
reist
|
||||||
|
rollt
|
||||||
|
rotem
|
||||||
|
roten
|
||||||
|
roter
|
||||||
|
rotes
|
||||||
|
rufen
|
||||||
|
ruhen
|
||||||
|
ruhig
|
||||||
|
runde
|
||||||
|
räume
|
||||||
|
räumt
|
||||||
|
rückt
|
||||||
|
sagen
|
||||||
|
sagte
|
||||||
|
sahen
|
||||||
|
sanft
|
||||||
|
satte
|
||||||
|
sauer
|
||||||
|
saßen
|
||||||
|
schuf
|
||||||
|
schön
|
||||||
|
sechs
|
||||||
|
sehen
|
||||||
|
seien
|
||||||
|
seine
|
||||||
|
sende
|
||||||
|
setze
|
||||||
|
setzt
|
||||||
|
siege
|
||||||
|
siehe
|
||||||
|
sieht
|
||||||
|
singt
|
||||||
|
sinkt
|
||||||
|
sitze
|
||||||
|
sitzt
|
||||||
|
sogar
|
||||||
|
solch
|
||||||
|
solle
|
||||||
|
sollt
|
||||||
|
somit
|
||||||
|
sonst
|
||||||
|
sorge
|
||||||
|
sorgt
|
||||||
|
sowie
|
||||||
|
spare
|
||||||
|
spart
|
||||||
|
spitz
|
||||||
|
späte
|
||||||
|
spürt
|
||||||
|
stahl
|
||||||
|
stand
|
||||||
|
starb
|
||||||
|
stark
|
||||||
|
statt
|
||||||
|
stehe
|
||||||
|
steht
|
||||||
|
stets
|
||||||
|
stich
|
||||||
|
stieg
|
||||||
|
stieß
|
||||||
|
still
|
||||||
|
stolz
|
||||||
|
stoße
|
||||||
|
stört
|
||||||
|
stößt
|
||||||
|
suche
|
||||||
|
sucht
|
||||||
|
tanze
|
||||||
|
tanzt
|
||||||
|
taten
|
||||||
|
teile
|
||||||
|
teils
|
||||||
|
teilt
|
||||||
|
teuer
|
||||||
|
teure
|
||||||
|
tiefe
|
||||||
|
tolle
|
||||||
|
total
|
||||||
|
totem
|
||||||
|
toter
|
||||||
|
totes
|
||||||
|
traue
|
||||||
|
traut
|
||||||
|
treue
|
||||||
|
trieb
|
||||||
|
trink
|
||||||
|
tritt
|
||||||
|
trotz
|
||||||
|
träge
|
||||||
|
trägt
|
||||||
|
tätig
|
||||||
|
töten
|
||||||
|
tötet
|
||||||
|
unser
|
||||||
|
unten
|
||||||
|
unter
|
||||||
|
vagem
|
||||||
|
vagen
|
||||||
|
vager
|
||||||
|
vages
|
||||||
|
viele
|
||||||
|
volle
|
||||||
|
vorab
|
||||||
|
voran
|
||||||
|
vorne
|
||||||
|
wagen
|
||||||
|
wahre
|
||||||
|
waren
|
||||||
|
warnt
|
||||||
|
warst
|
||||||
|
warte
|
||||||
|
warum
|
||||||
|
wecke
|
||||||
|
weckt
|
||||||
|
weder
|
||||||
|
wegen
|
||||||
|
wehre
|
||||||
|
wehrt
|
||||||
|
weich
|
||||||
|
weist
|
||||||
|
weite
|
||||||
|
weiße
|
||||||
|
welch
|
||||||
|
wende
|
||||||
|
wenig
|
||||||
|
werbe
|
||||||
|
werde
|
||||||
|
werte
|
||||||
|
wider
|
||||||
|
widme
|
||||||
|
wiegt
|
||||||
|
wilde
|
||||||
|
wirbt
|
||||||
|
wirft
|
||||||
|
wirke
|
||||||
|
wirkt
|
||||||
|
wisse
|
||||||
|
wobei
|
||||||
|
wofür
|
||||||
|
woher
|
||||||
|
wohin
|
||||||
|
wohne
|
||||||
|
wohnt
|
||||||
|
wolle
|
||||||
|
womit
|
||||||
|
wovon
|
||||||
|
wuchs
|
||||||
|
wunde
|
||||||
|
wurde
|
||||||
|
wähle
|
||||||
|
wählt
|
||||||
|
wärme
|
||||||
|
zahle
|
||||||
|
zeige
|
||||||
|
zeigt
|
||||||
|
zeuge
|
||||||
|
zieht
|
||||||
|
ziele
|
||||||
|
zielt
|
||||||
|
zivil
|
||||||
|
zogen
|
||||||
|
zudem
|
||||||
|
zumal
|
||||||
|
zuvor
|
||||||
|
zwang
|
||||||
|
zwölf
|
||||||
|
zählt
|
||||||
|
zügig
|
||||||
|
Ämter
|
||||||
|
Ärger
|
||||||
|
Ärzte
|
||||||
|
Übung
|
||||||
|
älter
|
||||||
|
öffne
|
||||||
|
öfter
|
||||||
|
übrig
|
||||||
|
übten
|
||||||
|
@@ -5,7 +5,8 @@ import schule.ngb.zm.util.io.FileLoader;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
class FileLoaderTest {
|
class FileLoaderTest {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user