[JAVA] Diffusionssimulation von Tinte, die auf die Wasseroberfläche tropft

Ich habe es mit der folgenden Diffusionsgleichung gemacht.

U_{i,j}^{t+1} - U_{i,j}^{t} = D \times ( U_{i-1,j}^t - 2U_{i,j}^t + U^t_{i+1,j} ) + D \times ( U^t_{i,j-1} - 2U^t_{i,j} + U^t_{i,j+1})

Da ich versuche, mich auf vergangene Rennen einzulassen, gebe ich als Übung eine Bilddatei im ppm-Format aus.

InkFlow.java


package flow;

import java.io.FileWriter;
import java.io.IOException;

public class InkFlow{
	//Simulieren Sie die Diffusion von Tinte, die auf die Wasseroberfläche fällt
	static double INK = 255.; //Maximaler RGB-Wert
	static int mx; //Anzahl der horizontalen Maschen(Anzahl der Pixel im Bild? werden)
	static int my; //Vertikal
	static int fc=0; //Dateiname Variable

	public static void main(String[] args) throws IOException {
		/*******
		 *Aufbau(Hier ändern)
		 *******/
		//Wasseroberflächeneinstellung
		int x = 10; //Seitenlänge[cm]
		int y = 10; //Vertikale Länge[cm]

		//Orte, an denen Tinte abfällt (oben links, oben rechts, oben rechts, links, Mitte, rechts, unten links, unten rechts unten)
		boolean CPlace[][] = { // Cyan
				{false,false,false},
				{true,false,false},
				{false,false,false}
		};
		boolean MPlace[][] = { // Magenta
				{false,true,false},
				{false,false,false},
				{false,false,false}
		};
		boolean YPlace[][] = { // Yellow
				{false,false,false},
				{false,false,false},
				{false,true,false}
		};
		//Die Größe der Tinte, die herunterhängen soll
		int InkSize = 13;

		//Zeiteinstellung
		int t=0; //Anfangszeit 0[msec]
		int T=10000;     //Endzeit[msec]
		int ut = 1000;		//Zeit der Dateiausgabeeinheit[msec]
		int inkt = 5000; //Zeit, Tinte zu tropfen[msec]

		//Variablen für die Diffusion
		double ul = 0.1; //Einheitsabstand[cm]
		mx = (int) (x / ul);
		my = (int) (y / ul);
		double D = 0.25; //Diffusionskoeffizient(<0.25)

		LogSettings(x,y,InkSize,T,ut, inkt ,ul,mx,my,D); //Konfigurationsprotokoll

		/*******
		 *Initialisieren
		 *******/
		//Farbinitialisierung (weiß)
		double R[][] = InitialInk();
		double G[][] = InitialInk();
		double B[][] = InitialInk();

		//Tinte abtropfen lassen
		DipInk(CPlace, MPlace, YPlace, InkSize, R, G, B);
		Output(R, G, B);

		/*******
		 *Hauptschleife
		 *******/
		while(t++ <= T) { //Schleife bis zur Endzeit T.
			//Diffusion
			R = CalcDiffusion(R, D);
			G = CalcDiffusion(G, D);
			B = CalcDiffusion(B, D);
			//Tinte abtropfen lassen
			if(t < inkt) { //inkt msec hängen
				DipInk(CPlace, MPlace, YPlace, InkSize, R, G, B);
			}
			//Ausgabe
			if(t % ut == 0){
				Output(R, G, B);
			}
		}
		System.out.println("done");
	}

	/*******
	 *Verschiedene Methoden
	 *******/
	static double[][] InitialInk(){ //Tinteninitialisierung
		double a[][] = new double[mx][my];
		for(int i = 0; i < mx; i++) {
			for(int j = 0; j < my; j++) {
				a[i][j] = INK;
			}
		}
		return a;
	}

	static double[][] CalcDiffusion(double[][] a, double D){ //Diffusionsberechnung
		double b[][] = new double[mx][my];
		//Innere Berechnung
		for(int i=1;i<(mx-1);i++){
			for(int j=1;j<(my-1);j++){ //Diffusionsgleichung
				b[i][j] = a[i][j] + D * (a[i+1][j] + a[i-1][j] - 2*a[i][j]) + D * (a[i][j+1] + a[i][j-1] - 2*a[i][j]);
			}
		}
		//Äußere Berechnung
		for(int i=0;i<mx;i++){
			b[i][my-1] = b[i][my-2];
			b[i][0] = b[i][1];
		}
		for(int j=0;j<my;j++){
			b[mx-1][j] = b[mx-2][j];
			b[0][j] = b[1][j];
		}
		return b;
	}

	static void DipInk(boolean[][] CPlace, boolean[][] MPlace, boolean[][] YPlace, int InkSize, double[][] R, double[][] G, double[][] B) {
		for(int i = 0; i < CPlace.length; i++) {
			for(int j = 0; j < CPlace[0].length; j++) {
				if(CPlace[i][j] || MPlace[i][j] || YPlace[i][j]) {
					if(CPlace[i][j]) {
						DipWithInkSize(R, InkSize, i, j, 0);
					} else {
						DipWithInkSize(R, InkSize, i, j, 212);
					}
					if(MPlace[i][j]) {
						DipWithInkSize(G, InkSize, i, j, 0);
					} else {
						DipWithInkSize(G, InkSize, i, j, 212);
					}
					if(YPlace[i][j]) {
						DipWithInkSize(B, InkSize, i, j, 0);
					} else {
						DipWithInkSize(B, InkSize, i, j, 212);
					}
				}
			}
		}
	}
	static void DipWithInkSize(double[][] C, int InkSize, int a, int b, double val) {
		//Erhöhen Sie die Tintenmenge in einer Spirale entsprechend der Tintengröße
		C[(int) (mx*(2*a+1)/6)][(int) (my*(2*b+1)/6)] = val; //Erste Tinte
		int itr = 1;
		int i = 1;
		while(true) {
			for(int x = itr, y = 0; x > 0; x--,y++) {
				C[(int) (mx*(2*a+1)/6)+x][(int) (my*(2*b+1)/6)+y] = val;
				i++;
				if(i >= InkSize) {
					return;
				}
			}
			for(int x = 0, y = itr; y > 0; x--, y--) {
				C[(int) (mx*(2*a+1)/6)+x][(int) (my*(2*b+1)/6)+y] = val;
				i++;
				if(i >= InkSize) {
					return;
				}
			}
			for(int x = -itr, y = 0; x < 0; x++,y--) {
				C[(int) (mx*(2*a+1)/6)+x][(int) (my*(2*b+1)/6)+y] = val;
				i++;
				if(i >= InkSize) {
					return;
				}
			}
			for(int x = 0, y = -itr; y < 0; x++, y++) {
				C[(int) (mx*(2*a+1)/6)+x][(int) (my*(2*b+1)/6)+y] = val;
				i++;
				if(i >= InkSize) {
					return;
				}
			}
			itr++;
		}
	}

	static void Output(double[][] R, double[][] G, double[][] B) throws IOException { //Bilddatei(ppm-Format)Ausgabe von
		String fname = "3_" + fc++ + ".ppm";
		FileWriter fw = new FileWriter(fname);    // Difine file name
		// Header
		fw.write("P3 \r\n");
		fw.write("#The P3 means colors are in ASCII, then columns and rows, then 255 for max color, then RGB triplets \r\n");
		fw.write(mx + " " + my + " \r\n");
		fw.write("" + (int) INK + " \r\n");

		// Body
		for(int i = 0; i < mx; i++) {
			for(int j = 0; j < my; j++) {
				fw.write("" + (int) R[i][j] + " " + (int) G[i][j] + " " + (int) B[i][j]);
				fw.write(" \r\n");
			}
		}
		fw.close();
		System.out.println("output: " + fname);
	}

	static void LogSettings(int x, int y, int InkSize, int T, int ut, int inkt, double ul, int mx, int my, double D) {
		System.out.println("Wasseroberfläche(Horizontal x vertikal)  : " + x + " cm × " + y + " cm");
		System.out.println("Tintengröße: " + ul*ul*InkSize + " cm^2");
		System.out.println("Zeit zum Aufhängen:" + inkt + " msec");
		System.out.println("Endzeit: " + T + " msec");
		System.out.println("Zeiteinheit ausgeben: " + ut + " msec");
		System.out.println("Einheitsabstand: " + ul + " cm");
		System.out.println("Anzahl der horizontalen Maschen: " + mx);
		System.out.println("Anzahl der vertikalen Maschen: " + my);
		System.out.println("Diffusionskoeffizient: " + D);
		System.out.println("-*-*-*-");
		if(mx / 6 < InkSize) {
			System.out.println("InkSize ist zu groß");
		}
	}
}

In der Konsole lautet die Ausgabe wie folgt.

Wasseroberfläche(Horizontal x vertikal)  : 10 cm × 10 cm
Tintengröße: 0.13000000000000003 cm^2
Zeit zum Aufhängen:5000 msec
Endzeit: 10000 msec
Zeiteinheit ausgeben: 1000 msec
Einheitsabstand: 0.1 cm
Anzahl der horizontalen Maschen: 100
Anzahl der vertikalen Maschen: 100
Diffusionskoeffizient: 0.25
-*-*-*-
output: 3_0.ppm
output: 3_1.ppm
output: 3_2.ppm
output: 3_3.ppm
output: 3_4.ppm
output: 3_5.ppm
output: 3_6.ppm
output: 3_7.ppm
output: 3_8.ppm
output: 3_9.ppm
output: 3_10.ppm
done

Das Ausgabebild sollte wie folgt aussehen

3_0.png 3_1.png 3_2.png 3_3.png 3_4.png 3_5.png 3_6.png 3_7.png 3_8.png 3_9.png 3_10.png

Recommended Posts

Diffusionssimulation von Tinte, die auf die Wasseroberfläche tropft
Hinweis zum Pfad von request.getRequestDispatcher
Zeigen Sie Text über dem Bild an
Samshin über den Wert des versteckten Feldes
Rückblick auf die Grundlagen von Java
[Ruby on Rails] Bis zur Einführung von RSpec
Installieren Sie die neueste Version von Jenkins unter Ubuntu 16