Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Javakurs/Übungsaufgaben/DiffusionLimitedAggregation/Musterlösung: Unterschied zwischen den Versionen

K (fix alignment)
 
(2 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 3: Zeile 3:
  
 
public class DLA {
 
public class DLA {
 
 
public static void main(String[] args) {
 
public static void main(String[] args) {
// Feld fuer Kollisionsueberpruefung erstellen
+
// Feld erstellen, in dem gespeichert wird, ob an gegebenen Koordinaten
 +
// ein Partikel ist
 
int[][] field = new int[400][400];
 
int[][] field = new int[400][400];
  
// Grenzen fuer Koordinaten der Partikel aus field berechnen (.length
+
// Maximalwerte fuer Koordinaten der Partikel, lassen sich aus den
// verwenden)
+
// Dimensionen von field berechnen (.length verwenden)
 
int maxX = field.length;
 
int maxX = field.length;
 
int maxY = field[0].length;
 
int maxY = field[0].length;
Zeile 20: Zeile 20:
 
drawPad.setColor(Pad.white);
 
drawPad.setColor(Pad.white);
  
// "Samen" erzeugen. Also den ersten Partikel in der Mitte des Feldes
+
// "Samen" erzeugen, also den ersten Pixel aufs Feld setzen (Color:
// setzen (Color: Pad.white)
+
// Pad.white)
 +
// Hier: Pixel wird genau in die Mitte des Feldes gesetzt - andere
 +
// Startpixel waeren moeglich
 
setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white);
 
setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white);
  
// Radius des Partikels der am weitesten vom Zentrum entfernt ist
+
// Abstand des Partikels, der am weitesten vom Zentrum des Feldes
 +
// entfernt ist
 
int maxR = 0;
 
int maxR = 0;
 +
 +
// Falls der Startpunkt auch ein anderer sein kann als das Zentrum des
 +
// Feldes:
 +
// Berechne fuer alle bereits vorhandenen Partikel den Abstand zum
 +
// Zentrum des Feldes
 +
// speichere das Maximum dieser Abstaende in maxR
 
for (int x = 0; x < maxX; x++) {
 
for (int x = 0; x < maxX; x++) {
 
for (int y = 0; y < maxY; y++) {
 
for (int y = 0; y < maxY; y++) {
 
if (testPixel(field, x, y)) {
 
if (testPixel(field, x, y)) {
 
+
maxR = (int) Math.max(maxR, Math.sqrt(Math.pow((x - maxX / 2), 2) + Math.pow((y - maxY / 2), 2)));
maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(
 
(x - maxX / 2), 2)
 
+ Math.pow((y - maxY / 2), 2)));
 
 
}
 
}
 
}
 
}
 
}
 
}
  
// Abbruchbedingung
+
// Abbruchbedingung: Hat einer der Partikel sich aus dem Feld heraus
 +
// bewegt?
 
boolean isAtBorder = false;
 
boolean isAtBorder = false;
  
// Schleifenkopf, solange maxR nicht den Rand des Fensters
+
// Schleife: Erstelle solange neue Partikel, wie die Abbruchbedingung
// beruehrt, sollen neue Punkte gezeichnet werden
+
// false ist
 
while (!isAtBorder) {
 
while (!isAtBorder) {
// einen Punkt auf einem Kreis um den Mittelpunkt mit dem Radius
+
// auf einem gedachten Kreis um den Mittelpunkt mit Radius maxR + 20
// maxR+20 erzeugen
+
// einen Partikel "erzeugen"
 +
// d.h. die Koordinaten eines zufaelligen Punktes auf dem Kreisrand
 +
// berechnen
 +
// neuer Partikel ist somit an Position movingPixelX ; movingPixelY
 +
 
 
double x = Math.random() * 360;
 
double x = Math.random() * 360;
int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX
+
int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX / 2, 0, maxX);
/ 2, 0, maxX);
+
int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY / 2, 0, maxY);
int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY
 
/ 2, 0, maxY);
 
  
// Schleife zum bewegen des Partikels
+
// Nun Start der brownschen Bewegung
while (!isTouching(field, movingPixelX, movingPixelY)
+
// Partikel bewegt sich, bis er einen bereits vorhandenen Partikel
&& inRange(movingPixelX, movingPixelY, maxR + 30, maxX,
+
// beruehrt oder bis er das Feld verlaesst
maxY)) {
+
 
// Partikelkoordinaten zufaellig bewegen (moveRandom)
+
while (!isTouching(field, movingPixelX, movingPixelY) && inRange(movingPixelX, movingPixelY, maxR + 30, maxX, maxY)) {
 +
 
 +
// zufaelliges Verschieben des Partikels um +/- 1 Pixel mit
 +
// moveRandom
 
movingPixelX = moveRandom(movingPixelX);
 
movingPixelX = moveRandom(movingPixelX);
 
movingPixelY = moveRandom(movingPixelY);
 
movingPixelY = moveRandom(movingPixelY);
 
}
 
}
  
// Schleife zuende, ueberpruefe ob eine Beruehrung vorliegt:
+
// Brownsche Bewegung zu Ende - Ist Partikel auf einen bereits
 +
// vorhandenen Partikel gestossen?
 
if (isTouching(field, movingPixelX, movingPixelY)) {
 
if (isTouching(field, movingPixelX, movingPixelY)) {
 +
// Wenn ja: Partikel ist jetzt "fest" an dieser Stelle, zeichne
 +
// einen Punkt dort
 
// Farbwertberechnung fuer 1337 blau-Effekt
 
// Farbwertberechnung fuer 1337 blau-Effekt
int k = limit(
+
int k = limit(255 - (int) (255 * ((double) maxR * 2) / (double) maxX), 0, 255);
255 - (int) (255 * ((double) maxR * 2) / (double) maxX),
 
0, 255);
 
 
Color c = new Color(255, k, k);
 
Color c = new Color(255, k, k);
  
Zeile 71: Zeile 84:
 
setPixel(drawPad, field, movingPixelX, movingPixelY, c);
 
setPixel(drawPad, field, movingPixelX, movingPixelY, c);
  
// Radius zum Mittelpunkt berechnen,
+
// Abstand des neu gesetzten Partikels zum Mittelpunkt des
// wenn groesser als altes Maximum, ueberschreiben
+
// Feldes berechnen
maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(
+
// wenn groesser als alter maximaler Abstand maxR, dann Maximum
((double) movingPixelX - (double) maxX / 2), 2)
+
// mit neuem Abstandswert ueberschreiben
+ Math.pow(((double) movingPixelY - (double) maxY / 2),
+
maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(((double) movingPixelX - (double) maxX / 2), 2) + Math.pow(((double) movingPixelY - (double) maxY / 2), 2)));
2)));
+
 
if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX
+
// Falls der Partikel das Feld verlassen hat: Zeichnung ist
|| movingPixelY - 1 <= 0 || movingPixelY + 1 >= maxY) {
+
// fertig, setze Abbruchkriterium der aeusseren Schleife auf
 +
// true
 +
if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX || movingPixelY - 1 <= 0 || movingPixelY + 1 >= maxY) {
 
isAtBorder = true;
 
isAtBorder = true;
 
}
 
}
Zeile 88: Zeile 103:
 
}
 
}
  
// ...Math.toRadians(
+
public static void setPixel(Pad drawPad, int[][] field, int x, int y, Color c) {
 
+
/**
public static void setPixel(Pad drawPad, int[][] field, int x, int y,
+
* Pruefe, ob sich der Partikel an Koordinaten (x,y) innerhalb des
Color c) {
+
* Feldes befindet Wenn ja, speichere ihn fest im Feld an dieser Stelle
 
+
* zeichne dort einen Punkt
 +
*/
 
if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) {
 
if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) {
 
 
field[x][y] = 1;
 
field[x][y] = 1;
 
 
drawPad.setColor(c);
 
drawPad.setColor(c);
 
drawPad.drawDot(x, y);
 
drawPad.drawDot(x, y);
Zeile 118: Zeile 132:
 
*/
 
*/
 
public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) {
 
public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) {
 
 
// Mittelpunkt des Rechtecks ausrechen
 
// Mittelpunkt des Rechtecks ausrechen
 
int middleX = maxX / 2;
 
int middleX = maxX / 2;
 
int middleY = maxY / 2;
 
int middleY = maxY / 2;
 
 
// Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java
 
// Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java
 
// intigrierten Klasse "Math"
 
// intigrierten Klasse "Math"
int distance = (int) Math.sqrt(Math.pow((x - middleX), 2)
+
int distance = (int) Math.sqrt(Math.pow((x - middleX), 2) + Math.pow((y - middleY), 2));
+ Math.pow((y - middleY), 2));
 
 
 
 
if (distance < maxR) {
 
if (distance < maxR) {
 
return true;
 
return true;
 
}
 
}
 
 
return false;
 
return false;
 
}
 
}
Zeile 147: Zeile 156:
 
*/
 
*/
 
public static boolean isTouching(int[][] field, int x, int y) {
 
public static boolean isTouching(int[][] field, int x, int y) {
 
 
// ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu
 
// ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu
 
// lesen und zu verstehen
 
// lesen und zu verstehen
Zeile 156: Zeile 164:
 
return true;
 
return true;
 
}
 
}
 
 
return false;
 
return false;
 
// #TODO ergänzen
 
 
}
 
}
  
Zeile 179: Zeile 184:
 
y = limit(y, 0, field[0].length - 1);
 
y = limit(y, 0, field[0].length - 1);
 
// länge des zweiten arrays
 
// länge des zweiten arrays
 
 
if (field[x][y] > 0) {
 
if (field[x][y] > 0) {
 
return true;
 
return true;
 
}
 
}
 
 
return false;
 
return false;
 
}
 
}
Zeile 199: Zeile 202:
 
*/
 
*/
 
public static int limit(int value, int lower, int upper) {
 
public static int limit(int value, int lower, int upper) {
 
 
if (value < lower) {
 
if (value < lower) {
 
return lower;
 
return lower;
 
}
 
}
 
 
if (value > upper) {
 
if (value > upper) {
 
return upper;
 
return upper;
 
}
 
}
 
 
return value;
 
return value;
 
}
 
}
Zeile 219: Zeile 219:
 
*/
 
*/
 
public static int moveRandom(int movePixel) {
 
public static int moveRandom(int movePixel) {
 
 
// erstelle eine random-Zahl zwischen 1 und
 
// erstelle eine random-Zahl zwischen 1 und
 
int random = 1 + (int) (Math.random() * 3);
 
int random = 1 + (int) (Math.random() * 3);
Zeile 234: Zeile 233:
 
return movePixel + 1;
 
return movePixel + 1;
 
}
 
}
 
 
}
 
}
 
 
}
 
}
 
 
</pre>
 
</pre>

Aktuelle Version vom 4. März 2013, 19:29 Uhr

import java.awt.Color;

public class DLA {
	public static void main(String[] args) {
		// Feld erstellen, in dem gespeichert wird, ob an gegebenen Koordinaten
		// ein Partikel ist
		int[][] field = new int[400][400];

		// Maximalwerte fuer Koordinaten der Partikel, lassen sich aus den
		// Dimensionen von field berechnen (.length verwenden)
		int maxX = field.length;
		int maxY = field[0].length;

		// Fenster fuer Grafikausgabe vorbereiten und anzeigen
		Pad drawPad = new Pad();
		drawPad.setBackground(Pad.black);
		drawPad.setPadSize(maxX, maxY);
		drawPad.setVisible(true);
		drawPad.setColor(Pad.white);

		// "Samen" erzeugen, also den ersten Pixel aufs Feld setzen (Color:
		// Pad.white)
		// Hier: Pixel wird genau in die Mitte des Feldes gesetzt - andere
		// Startpixel waeren moeglich
		setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white);

		// Abstand des Partikels, der am weitesten vom Zentrum des Feldes
		// entfernt ist
		int maxR = 0;

		// Falls der Startpunkt auch ein anderer sein kann als das Zentrum des
		// Feldes:
		// Berechne fuer alle bereits vorhandenen Partikel den Abstand zum
		// Zentrum des Feldes
		// speichere das Maximum dieser Abstaende in maxR
		for (int x = 0; x < maxX; x++) {
			for (int y = 0; y < maxY; y++) {
				if (testPixel(field, x, y)) {
					maxR = (int) Math.max(maxR, Math.sqrt(Math.pow((x - maxX / 2), 2) + Math.pow((y - maxY / 2), 2)));
				}
			}
		}

		// Abbruchbedingung: Hat einer der Partikel sich aus dem Feld heraus
		// bewegt?
		boolean isAtBorder = false;

		// Schleife: Erstelle solange neue Partikel, wie die Abbruchbedingung
		// false ist
		while (!isAtBorder) {
			// auf einem gedachten Kreis um den Mittelpunkt mit Radius maxR + 20
			// einen Partikel "erzeugen"
			// d.h. die Koordinaten eines zufaelligen Punktes auf dem Kreisrand
			// berechnen
			// neuer Partikel ist somit an Position movingPixelX ; movingPixelY

			double x = Math.random() * 360;
			int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX / 2, 0, maxX);
			int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY / 2, 0, maxY);

			// Nun Start der brownschen Bewegung
			// Partikel bewegt sich, bis er einen bereits vorhandenen Partikel
			// beruehrt oder bis er das Feld verlaesst

			while (!isTouching(field, movingPixelX, movingPixelY) && inRange(movingPixelX, movingPixelY, maxR + 30, maxX, maxY)) {

				// zufaelliges Verschieben des Partikels um +/- 1 Pixel mit
				// moveRandom
				movingPixelX = moveRandom(movingPixelX);
				movingPixelY = moveRandom(movingPixelY);
			}

			// Brownsche Bewegung zu Ende - Ist Partikel auf einen bereits
			// vorhandenen Partikel gestossen?
			if (isTouching(field, movingPixelX, movingPixelY)) {
				// Wenn ja: Partikel ist jetzt "fest" an dieser Stelle, zeichne
				// einen Punkt dort
				// Farbwertberechnung fuer 1337 blau-Effekt
				int k = limit(255 - (int) (255 * ((double) maxR * 2) / (double) maxX), 0, 255);
				Color c = new Color(255, k, k);

				// den Partikel setzen und zeichnen
				setPixel(drawPad, field, movingPixelX, movingPixelY, c);

				// Abstand des neu gesetzten Partikels zum Mittelpunkt des
				// Feldes berechnen
				// wenn groesser als alter maximaler Abstand maxR, dann Maximum
				// mit neuem Abstandswert ueberschreiben
				maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(((double) movingPixelX - (double) maxX / 2), 2) + Math.pow(((double) movingPixelY - (double) maxY / 2), 2)));

				// Falls der Partikel das Feld verlassen hat: Zeichnung ist
				// fertig, setze Abbruchkriterium der aeusseren Schleife auf
				// true
				if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX || movingPixelY - 1 <= 0 || movingPixelY + 1 >= maxY) {
					isAtBorder = true;
				}

			}
			// System.out.println(maxX + "\t" + maxY + "\t " + maxR + "\t"
			// + movingPixelX + "\t" + movingPixelY + "\t"+isAtBorder);
		}
	}

	public static void setPixel(Pad drawPad, int[][] field, int x, int y, Color c) {
		/**
		 * Pruefe, ob sich der Partikel an Koordinaten (x,y) innerhalb des
		 * Feldes befindet Wenn ja, speichere ihn fest im Feld an dieser Stelle
		 * zeichne dort einen Punkt
		 */
		if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) {
			field[x][y] = 1;
			drawPad.setColor(c);
			drawPad.drawDot(x, y);
		}
	}

	/**
	 * Prüft ob sich ein Punkt innerhalb eines Radius vom Mittelpunkt eines
	 * Rechtecks befindet
	 * 
	 * @param x
	 *            die x Koordinate des fields
	 * @param y
	 *            die y Koordinate des fields
	 * @param maxR
	 *            der Radius
	 * @param maxX
	 *            die x Koordinate des Rechtecks
	 * @param maxY
	 *            die y Koordinate des Rechtecks+30
	 */
	public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) {
		// Mittelpunkt des Rechtecks ausrechen
		int middleX = maxX / 2;
		int middleY = maxY / 2;
		// Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java
		// intigrierten Klasse "Math"
		int distance = (int) Math.sqrt(Math.pow((x - middleX), 2) + Math.pow((y - middleY), 2));
		if (distance < maxR) {
			return true;
		}
		return false;
	}

	/**
	 * Testet ob das gegebene Pixel an ein anderes grenzt
	 * 
	 * @param field
	 *            das Array von Pixeln
	 * @param x
	 *            die x Koordinate des fields
	 * @param y
	 *            die y Koordinate des fields
	 * @return grenzt an ein anders Pixel (true) oder nicht (false)
	 */
	public static boolean isTouching(int[][] field, int x, int y) {
		// ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu
		// lesen und zu verstehen
		if (testPixel(field, x - 1, y - 1) || testPixel(field, x - 1, y)
				|| testPixel(field, x - 1, y + 1) || testPixel(field, x, y - 1)
				|| testPixel(field, x, y + 1) || testPixel(field, x + 1, y - 1)
				|| testPixel(field, x + 1, y) || testPixel(field, x + 1, y + 1)) {
			return true;
		}
		return false;
	}

	/**
	 * Testet ob der Wert des Pixels größer 0 ist. (Falls der Wert außerhalb der
	 * Grenzen ist wird er mit der limit() Methode gelimited)
	 * 
	 * @param field
	 *            das Array von Pixeln
	 * @param x
	 *            die x Koordinate des fields
	 * @param y
	 *            die y Koordinate des fields
	 * @return ob der Wert größer 0 ist (true) oder nicht (false)
	 */
	public static boolean testPixel(int[][] field, int x, int y) {
		// länge des ersten arrays
		x = limit(x, 0, field.length - 1);
		y = limit(y, 0, field[0].length - 1);
		// länge des zweiten arrays
		if (field[x][y] > 0) {
			return true;
		}
		return false;
	}

	/**
	 * Limitiert einen Wert auf einen Bereich
	 * 
	 * @param value
	 *            der zu limitierende Wert
	 * @param lower
	 *            die untere Grenze
	 * @param upper
	 *            die obere Grenze
	 * @return den limitierten Wert
	 */
	public static int limit(int value, int lower, int upper) {
		if (value < lower) {
			return lower;
		}
		if (value > upper) {
			return upper;
		}
		return value;
	}

	/**
	 * Bewegt eine Pixelkoordinate randommäßig -1, +1 oder gar nicht
	 * 
	 * @param movePixel
	 *            die zu bewegende Pixel-Koordinate
	 * @return die Bewegte Pixel-Koordinate
	 */
	public static int moveRandom(int movePixel) {
		// erstelle eine random-Zahl zwischen 1 und
		int random = 1 + (int) (Math.random() * 3);
		// Math.random() gibt eine double-Zahl >= 0.0 und < 1.0 zurück
		switch (random) {

		case 1:
			return movePixel - 1;

		case 2:
			return movePixel;

		default:
			return movePixel + 1;
		}
	}
}