Can anyone help me understand how to simulate fluids? - java

I'm trying to make a program that simulates the physics of fluids in Processing. In the IDE there's an included example:
/**
* Fluid
* by Glen Murphy.
*
* Click and drag the mouse to move the simulated fluid.
* Adjust the "res" variable below to change resolution.
* Code has not been optimised, and will run fairly slowly.
*/
int res = 2;
int penSize = 30;
int lwidth;
int lheight;
int pnum = 30000;
vsquare[][] v;
vbuffer[][] vbuf;
particle[] p = new particle[pnum];
int pcount = 0;
int mouseXvel = 0;
int mouseYvel = 0;
void setup()
{
size(200, 200);
noStroke();
frameRate(30);
lwidth = width/res;
lheight = height/res;
v = new vsquare[lwidth+1][lheight+1];
vbuf = new vbuffer[lwidth+1][lheight+1];
for (int i = 0; i < pnum; i++) {
p[i] = new particle(random(res,width-res),random(res,height-res));
}
for (int i = 0; i <= lwidth; i++) {
for (int u = 0; u <= lheight; u++) {
v[i][u] = new vsquare(i*res,u*res);
vbuf[i][u] = new vbuffer(i*res,u*res);
}
}
}
void draw()
{
background(#666666);
int axvel = mouseX-pmouseX;
int ayvel = mouseY-pmouseY;
mouseXvel = (axvel != mouseXvel) ? axvel : 0;
mouseYvel = (ayvel != mouseYvel) ? ayvel : 0;
for (int i = 0; i < lwidth; i++) {
for (int u = 0; u < lheight; u++) {
vbuf[i][u].updatebuf(i,u);
v[i][u].col = 32;
}
}
for (int i = 0; i < pnum-1; i++) {
p[i].updatepos();
}
for (int i = 0; i < lwidth; i++) {
for (int u = 0; u < lheight; u++) {
v[i][u].addbuffer(i, u);
v[i][u].updatevels(mouseXvel, mouseYvel);
v[i][u].display(i, u);
}
}
}
class particle {
float x;
float y;
float xvel;
float yvel;
int pos;
particle(float xIn, float yIn) {
x = xIn;
y = yIn;
}
void updatepos() {
float col1;
if (x > 0 && x < width && y > 0 && y < height) {
int vi = (int)(x/res);
int vu = (int)(y/res);
vsquare o = v[vi][vu];
float ax = (x%res)/res;
float ay = (y%res)/res;
xvel += (1-ax)*v[vi][vu].xvel*0.05;
yvel += (1-ay)*v[vi][vu].yvel*0.05;
xvel += ax*v[vi+1][vu].xvel*0.05;
yvel += ax*v[vi+1][vu].yvel*0.05;
xvel += ay*v[vi][vu+1].xvel*0.05;
yvel += ay*v[vi][vu+1].yvel*0.05;
o.col += 4;
x += xvel;
y += yvel;
}
else {
x = random(0,width);
y = random(0,height);
xvel = 0;
yvel = 0;
}
xvel *= 0.5;
yvel *= 0.5;
}
}
class vbuffer {
int x;
int y;
float xvel;
float yvel;
float pressurex = 0;
float pressurey = 0;
float pressure = 0;
vbuffer(int xIn,int yIn) {
x = xIn;
y = yIn;
pressurex = 0;
pressurey = 0;
}
void updatebuf(int i, int u) {
if (i>0 && i<lwidth && u>0 && u<lheight) {
pressurex = (v[i-1][u-1].xvel*0.5 + v[i-1][u].xvel + v[i-1][u+1].xvel*0.5 - v[i+1][u-1].xvel*0.5 - v[i+1][u].xvel - v[i+1][u+1].xvel*0.5);
pressurey = (v[i-1][u-1].yvel*0.5 + v[i][u-1].yvel + v[i+1][u-1].yvel*0.5 - v[i-1][u+1].yvel*0.5 - v[i][u+1].yvel - v[i+1][u+1].yvel*0.5);
pressure = (pressurex + pressurey)*0.25;
}
}
}
class vsquare {
int x;
int y;
float xvel;
float yvel;
float col;
vsquare(int xIn,int yIn) {
x = xIn;
y = yIn;
}
void addbuffer(int i, int u) {
if (i>0 && i<lwidth && u>0 && u<lheight) {
xvel += (vbuf[i-1][u-1].pressure*0.5
+vbuf[i-1][u].pressure
+vbuf[i-1][u+1].pressure*0.5
-vbuf[i+1][u-1].pressure*0.5
-vbuf[i+1][u].pressure
-vbuf[i+1][u+1].pressure*0.5
)*0.25;
yvel += (vbuf[i-1][u-1].pressure*0.5
+vbuf[i][u-1].pressure
+vbuf[i+1][u-1].pressure*0.5
-vbuf[i-1][u+1].pressure*0.5
-vbuf[i][u+1].pressure
-vbuf[i+1][u+1].pressure*0.5
)*0.25;
}
}
void updatevels(int mvelX, int mvelY) {
if (mousePressed) {
float adj = x - mouseX;
float opp = y - mouseY;
float dist = sqrt(opp*opp + adj*adj);
if (dist < penSize) {
if (dist < 4) dist = penSize;
float mod = penSize/dist;
xvel += mvelX*mod;
yvel += mvelY*mod;
}
}
xvel *= 0.99;
yvel *= 0.99;
}
void display(int i, int u) {
float tcol = 0;
if (col > 255) col = 255;
if (i>0 && i<lwidth-1 && u>0 && u<lheight-1) {
tcol = (+ v[i][u+1].col
+ v[i+1][u].col
+ v[i+1][u+1].col*0.5
)*0.4;
tcol = (int)(tcol+col*0.5);
}
else {
tcol = (int)col;
}
fill(tcol, tcol, tcol);
rect(x,y,res,res);
}
}
It's not really commented and I'm somewhat new to programming, so I have no idea where to start as far as understanding it. Is there any good reading on fluid physics? I'm more interesting in the visual effect than the accuracy of the simulation.

A good starting point could be the paper Stable Fluids, it will show you the math behind the fluid simulation, and in the third chapter it describe the implementation of a fluid solver. There is also an open source implementation available in sourceforge (you will need to checkout the source with cvs).

Related

Freeze moving rectangles

I'm working on a project where we are supposed to have rectangles of random sizes bounce off a wall and change color each time they bounce.
When you click on them, they are supposed to freeze in place and turn red. I'm just having trouble having them stop and for some reason they slow when one is clicked.
import java.util.Random;
public class Main {
public static void main(String[] args) {
MovingRectangles[] rectangles = new MovingRectangles[5];
Random rng = new Random();
for (int i = 0; i < rectangles.length; i++) {
rectangles[i] = new MovingRectangles(rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
}
for (int g = 0; g < rectangles.length; g++) {
rectangles[g] = new MovingRectangles(
rng.nextDouble(),
rng.nextDouble(),
rng.nextDouble() / 50 - 0.01,
rng.nextDouble() / 50 - 0.01,
rng.nextDouble() * 0.04 + 0.03,
rng.nextDouble() * 0.04 + 0.03
);
}
while (true) {
StdDraw.clear();
for (int h = 0; h < rectangles.length; h++) {
rectangles[h].draw();
rectangles[h].update();
}
int count = 0;
for (int i =0; i < rectangles.length; i++) {
rectangles[i].draw();
if (StdDraw.mousePressed() && rectangles[i].containsPoint(StdDraw.mouseX(), StdDraw.mouseY())) {
rectangles[i].freeze();
}
if (rectangles[i].isFrozen()) {
count++;
StdDraw.show(25);
}
}
}
}}
This is the class for moving rectangles. Stackoverflow says I need to add context to explain what this code is.
import java.util.Random;
public class MovingRectangles {
private double x;
private double y;
private double vx;
private double vy;
private double hx;
private double hy;
private boolean isFrozen;
private int red;
private int green;
private int blue;
public MovingRectangles(double x, double y, double vx, double vy, double hx, double hy) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
isFrozen = false;
this.hx = hx;
this.hy = hy;
randomColor();
}
public void randomColor() {
Random rng = new Random();
red = rng.nextInt(256);
blue = rng.nextInt(256);
green = rng.nextInt(256);
}
public void draw() {
if (isFrozen) {
StdDraw.setPenColor(StdDraw.RED);
} else {
StdDraw.setPenColor(red, green, blue);
}
StdDraw.filledRectangle(x, y, hx, hy);
}
public void update() {
x += vx;
y += vy;
if (x - hx < 0) {
vx *= -1;
x = 0 + hx;
randomColor();
}
if (x + hx > 1) {
vx *= -1;
x = 1 - hx;
randomColor();
}
if (y - hy < 0) {
vy *= -1;
y = 0 + hy;
randomColor();
}
if (y + hy > 1) {
vy *= -1;
y = 1 - hy;
randomColor();
}
}
public void freeze() {
isFrozen = true;
}
public boolean isFrozen() {
return isFrozen;
}
public boolean containsPoint(double a, double b) {
return
a > x - hx &&
a < x + hx &&
b > y - hy &&
b < y + hy;
}
}
The only other thing I need to add is for it to print "You Win" when all five of the boxes have been clicked. thanks for any help.
My thought is that you're not stopping the actual update of the rectangle.
In your MovingRectangles class...
public void update() {
if(!this.isFrozen) {
{...your code...}
}
}
add at the very beginning of update method line like
if(isFrozen) return;
it should stop your rectangle.
the another way (if you don't want to touch rectangle class).
after
for (int h = 0; h < rectangles.length; h++) {
rectangles[h].draw();
add
if(!rectangles[h].isFrozen()) rectangles[h].update();
This update to draw fixed the problem I was having.
public void draw() {
if (isFrozen) {
StdDraw.setPenColor(StdDraw.RED);
StdDraw.filledRectangle(x, y, hx, hy);
vx = 0;
vy = 0;
} else {
StdDraw.setPenColor(red, green, blue);
}
StdDraw.filledRectangle(x, y, hx, hy);
}

keeping sprites from colliding java

I am making a game in java and I have most of it done. However, one of the last bugs i need to fix is that enemy sprites can overlap each other and spawn on top of one another off screen. I want to make it so if enemy sprites collide they can only touch but not overlap. here is the code for the enemy class.
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Enemy extends Base {
int x;
int y;
int velx = -2;
int vely = 0;
public Enemy(int x, int y) {
super(x,y);
this.x = x;
this.y = y;
}
public void update() {
movement();
x += velx;
y += vely;
if (x < - 15) {
x = -15;
movement();
}
if (x > 1100) {
x = 1100;
movement();
}
if (y > 660) {
y = 660;
movement();
}
if (y < 10) {
y = 10;
movement();
}
}
public void draw(Graphics g) {
g.drawImage(getEnemyImage(), x, y, null);
}
public static Image getEnemyImage(){
ImageIcon ic = new ImageIcon("enemy.gif");
return ic.getImage();
}
public Rectangle getBounds(){
return new Rectangle(x, y, getEnemyImage().getWidth(null), getEnemyImage().getHeight(null));
}
public void checkColision(){
ArrayList<Base> enemies = GamePanel.getEnemyList();
if (x <= 0) {
velx = 2;
}
if (x >= 1096) {
velx = -2;
}
for (int a = 0; a < enemies.size(); a++) {
Base temp = GamePanel.enemy.get(a);
if (getBounds().intersects(temp.getBounds())) {
// where the collision check should happen.
}
}
}
public void movement(){
if (y > 16) {
if (x > GamePanel.p.getX()) {
velx = - 2;
}
if (x < GamePanel.p.getX()) {
velx = 2;
}
if (y > GamePanel.p.getY()) {
vely = -2;
}
if (y < GamePanel.p.getY()) {
vely = 2;
}
}
}
}
and this is where the enemies are spawned.
for (int a = 0; a < enemy_amount; a++) {
space += 50;
int rand = (int)(Math.random() * 2) + 1;
if (rand == 1) {
int randp = (int)(Math.random() * 2) + 1;
int x = 0;
int y = 0;
if (randp == 1) {
x = 1250 + space;
y = 500;
}
if (randp == 2) {
x = 1250 + space;
y = 100;
}
enemy.add(new Enemy(x,y));
}
if (rand == 2) {
int randp = (int)(Math.random() * 2) + 1;
int x = 0;
int y = 0;
if (randp == 1) {
x = 250;
y = -100 - space;
}
if (randp == 2) {
x = 850;
y = -100 - space;
}
enemy.add(new Enemy2(x,y));
}
}
any help would be great because i am really stuck.

Perlin Noise Generation not functioning properly

I have been working with perlin noise recently and when implementing it into a tile engine I am using, I have noticed that the perlin noise function produced "blocks" as seen in the picture below. Each pixel is another different location in a 500 by 500 array that is returned from the perlin noise function.
in this example the persistence is 0.5 with an octave count of 5
When playing with it further, the more octaves I have, the larger the block chunks.
Here is the Code that I am using to call the perlin noise function:
PerlinNoise p = new PerlinNoise();
//returns a float[][] array of 500 by 500
p.GeneratePerlinNoise(p.genWhiteNoise(500, 500), 5, (float) 0.1);
PerlinNoise class
import java.util.Random;
public class PerlinNoise {
Random r;
public PerlinNoise() {
r = new Random();
}
public void setSeed(long seed) {
r.setSeed(seed);
}
public void printOutArray(float[][] arr) {
for(int i = 0; i < arr.length; i++) {
for(int n = 0; n < arr[0].length; n++) {
System.out.print(arr[i][n] + ", ");
}
System.out.print("\n");
}
}
public void printOutTerrain(float[][] arr) {
for(int i = 0; i < arr.length; i++) {
for(int n = 0; n < arr[0].length; n++) {
float a = arr[i][n];
if(a < 0.4) {
System.out.print("W");
} else {
System.out.print("L");
}
}
System.out.print("\n");
}
}
//-------------------------------------------------------------//
float[][] genWhiteNoise(int width, int height) {
float[][] noise = new float[height][width];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
noise[y][x] = r.nextFloat();
}
}
return noise;
}
float[][] genSmoothNoise(float[][] baseNoise, int octave) {
int height = baseNoise.length;
int width = baseNoise[0].length;
float[][] smoothNoise = new float[height][width];
int samplePeriod = 1 << octave; //calculates 2^k
float sampleFrequency = (float) (1.0/samplePeriod);
for(int i = 0; i < height; i++) {
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % height; //wrap around
float vertical_blend = (i - sample_i0) * sampleFrequency;
for(int n = 0; n < width; n++) {
int sample_n0 = (n / samplePeriod) * samplePeriod;
int sample_n1 = (sample_n0 + samplePeriod) % width; //wrap around
float horizontal_blend = (n - sample_n0) * sampleFrequency;
//blend the top two corners
float top = Interpolate(baseNoise[sample_i0][sample_n0],
baseNoise[sample_i1][sample_n0], horizontal_blend);
//blend the bottom two corners
float bottom = Interpolate(baseNoise[sample_i0][sample_n1],
baseNoise[sample_i1][sample_n1], horizontal_blend);
//final blend
smoothNoise[i][n] = Interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount, float persistance)
{
int height = baseNoise.length;
int width = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = genSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[height][width];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalisation
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
//linear average between two points
float Interpolate(float x0, float x1, float alpha)
{
return Cosine_Interpolate(x0, x1, alpha);
}
//Linear Interpolation
float Linear_Interpolate(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
//Cosine interpolation (much smoother)
float Cosine_Interpolate(float x0, float x1, float alpha)
{
float ft = (float) (alpha * 3.141592653589);
float f = (float) ((1 - Math.cos(ft)) * 0.5);
return x0*(1-f) + x1*f;
}
}
So to reiterate my question: Why is my perlin noise function behaving the way it does, as in only generating space in chunks?
So to fix this, all I had to do is swap the vertical_blend and horizontal_blend variables in the genSmoothNoise() method. It's amazing what you notice after a break

How can I make the image move in a random position?

I have an image inside the panel and it moves in a clockwise direction. Now, I want it to move in a random direction and that is my problem.
Could someone give me an idea how to do it?
Here's what I've tried :
private int xVelocity = 1;
private int yVelocity = 1;
private int x, y;
private static final int RIGHT_WALL = 400;
private static final int UP_WALL = 1;
private static final int DOWN_WALL = 400;
private static final int LEFT_WALL = 1;
public void cycle()
{
x += xVelocity;
if (x >= RIGHT_WALL)
{
x = RIGHT_WALL;
if (y >= UP_WALL)
{
y += yVelocity;
}
}
if (y > DOWN_WALL)
{
y = DOWN_WALL;
if (x >= LEFT_WALL)
{
xVelocity *= -1;
}
}
if (x <= LEFT_WALL)
{
x = LEFT_WALL;
if (y <= DOWN_WALL)
{
y -= yVelocity;
}
}
if (y < UP_WALL)
{
y = UP_WALL;
if (x <= RIGHT_WALL)
{
xVelocity *= -1;
}
}
}
Call a method like this to set a random direction:
public void setRandomDirection() {
double direction = Math.random()*2.0*Math.PI;
double speed = 10.0;
xVelocity = (int) (speed*Math.cos(direction));
yVelocity = (int) (speed*Math.sin(direction));
}
Just noticed that you're cycle method will need a little fixing for this to work.
public void cycle() {
x += xVelocity;
y += yVelocity; //added
if (x >= RIGHT_WALL) {
x = RIGHT_WALL;
setRandomDirection();//bounce off in a random direction
}
if (x <= LEFT_WALL) {
x = LEFT_WALL;
setRandomDirection();
}
if (y >= DOWN_WALL) {
y = DOWN_WALL;
setRandomDirection();
}
if (y <= UP_WALL) {
y = UP_WALL;
setRandomDirection();
}
}
(It works, but this is not the most efficient/elegant way to do it)
And if you want some sort of 'random walk' try something like this:
public void cycle() {
//move forward
x += xVelocity;
y += yVelocity;
if (Math.random() < 0.1) {//sometimes..
setRandomDirection(); //..change course to a random direction
}
}
You can increase 0.1 (max 1.0) to make it move more shaky.
Change
y -= yVelocity;
To
if (y>0) {
y = -1*Random.nextInt(3);
} else {
y = Random.nextInt(3);
}

Bounding box doesn't work properly - /withkinect

I am trying to make a bounding box over the blue-colored pixels (from Kinect v1 camera, using Processing). Y-axis of bounding box works perfectly but x-axis is very off.
void display() {
PImage img = kinect.getDepthImage();
float maxValue = 0;
float minValue = kinect.width*kinect.height ;
float maxValueX = 0;
float maxValueY = 0;
float minValueX = kinect.width;
float minValueY = kinect.height;
// Being overly cautious here
if (depth == null || img == null) return;
display.loadPixels();
for (int x = 0; x < kinect.width; x++) { //goes through all the window
for (int y = 0; y < kinect.height; y++) {
int offset = x + y * kinect.width;
// Raw depth
int rawDepth = depth[offset];
int pix = x + y * display.width; //why is it y*width
if (rawDepth < threshold) {
// A blue color instead
display.pixels[pix] = color(0, 0, 255); //set correct pixels to blue
if(pix > maxValue){
maxValue = pix;
maxValueX = x;
maxValueY = y;
}
if(pix < minValue){
minValue = pix;
minValueX = x;
minValueY = y;
}
} else {
display.pixels[pix] = img.pixels[offset];
}
}
}
display.updatePixels();
image(display, 0, 0);
rect(minValueX, minValueY, maxValueX-minValueX, maxValueY-minValueY);
}
You have to calculate the minimum and maximum values for each index or coordinate separately. Use the min respectively max function for this:
maxValue = max(maxValue, pix);
minValue = min(minValue, pix);
maxValueX = max(maxValueX, x);
minValueX = min(minValueX, x);
maxValueY = max(maxValueY, y);
minValueY = min(minValueY, y);
or with an ifstatement:
if (pix > maxValue) { maxValue = pix; }
if (pix < minValue) { minValue = pix; }
if (x > maxValueX) { maxValueX = x; }
if (x < minValueX) { minValueX = x; }
if (y > maxValueY) { maxValueY = y; }
if (y < minValueY) { minValueY = y; }

Categories