using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Net;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Animation;
using
System.Windows.Shapes;
using
System.Threading;
using
System.Windows.Threading;
namespace
fluent
{
public
partial
class
MainPage : UserControl
{
LiquidTest lt;
DispatcherTimer dispatcher
=
new
DispatcherTimer();
public
MainPage()
{
InitializeComponent();
lt
=
new
LiquidTest(
100
,
100
,
50
,
50
);
lt.init();
//
CompositionTarget.Rendering+=RenderFrame;
dispatcher.Tick
+=
new
EventHandler(changePage_Tick);
dispatcher.Interval
=
new
TimeSpan(
0
,
0
,
0
,
0
,
10
);
canvas
=
LayoutRoot;
}
private
void
changePage_Tick(
object
sender, EventArgs e)
{
Path path
=
canvas.Children[
1
]
as
Path;
path.ClearValue(Path.DataProperty);
foreach
(Particle p
in
lt.particles)
{
//
var p = this.particles[pi];
line(
4.0
*
p.x,
4.0
*
p.y,
4.0
*
(p.x
-
p.u),
4.0
*
(p.y
-
p.v));
}
lt.simulate();
}
private
void
Button_Click(
object
sender, RoutedEventArgs e)
{
dispatcher.Start();
running
=
true
;
step
=
1
;
}
Canvas canvas;
//
var context;
bool
running
=
false
;
int
width
=
0
;
int
height
=
0
;
//
var liquidTest;
int
step
=
1
;
class
Material
{
public
double
m;
public
double
rd;
public
double
k;
public
double
v;
public
double
d;
public
double
g;
public
Material(
double
m,
double
rd,
double
k,
double
v,
double
d,
double
g)
{
this
.m
=
m;
this
.rd
=
rd;
this
.k
=
k;
this
.v
=
v;
this
.d
=
d;
this
.g
=
g;
}
}
class
Node
{
public
double
m
=
0
;
public
double
d
=
0
;
public
double
gx
=
0
;
public
double
gy
=
0
;
public
double
u
=
0
;
public
double
v
=
0
;
public
double
ax
=
0
;
public
double
ay
=
0
;
public
bool
active
=
false
;
public
void
clear()
{
this
.m
=
this
.d
=
this
.gx
=
this
.gy
=
this
.u
=
this
.v
=
this
.ax
=
this
.ay
=
0.0
;
active
=
false
;
}
}
class
Particle
{
public
Material mat;
public
double
x
=
0
, y
=
0
;
public
double
u
=
0
, v
=
0
;
public
Particle(Material mat,
double
x,
double
y,
double
u,
double
v)
{
this
.mat
=
mat;
this
.x
=
x;
this
.y
=
y;
this
.u
=
u;
this
.v
=
v;
}
public
double
dudx
=
0
;
public
double
dudy
=
0
;
public
double
dvdx
=
0
;
public
double
dvdy
=
0
;
public
int
cx
=
0
;
public
int
cy
=
0
;
public
double
[] px
=
new
double
[] {
0
,
0
,
0
};
public
double
[] py
=
new
double
[] {
0
,
0
,
0
};
public
double
[] gx
=
new
double
[] {
0
,
0
,
0
};
public
double
[] gy
=
new
double
[] {
0
,
0
,
0
};
}
class
LiquidTest
{
int
gsizeX;
int
gsizeY;
int
particlesX;
int
particlesY;
public
LiquidTest(
int
gsizeX,
int
gsizeY,
int
particlesX,
int
particlesY)
{
this
.gsizeX
=
gsizeX;
this
.gsizeY
=
gsizeY;
this
.particlesX
=
particlesX;
this
.particlesY
=
particlesY;
}
public
List
<
Particle
>
particles
=
new
List
<
Particle
>
();
List
<
List
<
Node
>>
grid
=
new
List
<
List
<
Node
>>
();
List
<
Node
>
active
=
new
List
<
Node
>
();
//
Nodes
Material water
=
new
Material(
1.0
,
1.0
,
1.0
,
1.0
,
1.0
,
1.0
);
//
this.pressed = false;
//
this.pressedprev = false;
double
mx
=
0
;
double
my
=
0
;
double
mxprev
=
0
;
double
myprev
=
0
;
public
void
init()
{
int
i
=
0
, j
=
0
;
for
(i
=
0
; i
<
this
.gsizeX; i
++
)
{
List
<
Node
>
nodes
=
new
List
<
Node
>
();
for
(j
=
0
; j
<
this
.gsizeY; j
++
)
{
nodes.Add(
new
Node());
}
grid.Add(nodes);
}
Particle p;
for
(i
=
0
; i
<
particlesX; i
++
)
for
(j
=
0
; j
<
particlesY; j
++
)
{
p
=
new
Particle(water, i
+
4
, j
+
4
,
0.0
,
0.0
);
this
.particles.Add(p);
}
}
public
void
simulate()
{
bool
drag
=
false
;
double
mdx
=
0.0
, mdy
=
0.0
;
//
if (this.pressed && this.pressedprev)
//
{
//
drag = true;
//
mdx = 0.25 * (this.mx - this.mxprev);
//
mdy = 0.25 * (this.my - this.myprev);
//
}
//
this.pressedprev = this.pressed;
this
.mxprev
=
this
.mx;
this
.myprev
=
this
.my;
foreach
(Node n
in
this
.active)
{
n.clear();
}
this
.active.Clear();
double
x, y, phi;
double
fx
=
0.0
, fy
=
0.0
;
foreach
(Particle p
in
this
.particles)
{
//
var p = this.particles[pi];
p.cx
=
(
int
)(p.x
-
0.5
);
p.cy
=
(
int
)(p.y
-
0.5
);
x
=
p.cx
-
p.x;
p.px[
0
]
=
(
0.5
*
x
*
x
+
1.5
*
x
+
1.125
);
p.gx[
0
]
=
(x
+
1.5
);
x
+=
1.0
;
p.px[
1
]
=
(
-
x
*
x
+
0.75
);
p.gx[
1
]
=
(
-
2.0
*
x);
x
+=
1.0
;
p.px[
2
]
=
(
0.5
*
x
*
x
-
1.5
*
x
+
1.125
);
p.gx[
2
]
=
(x
-
1.5
);
y
=
p.cy
-
p.y;
p.py[
0
]
=
(
0.5
*
y
*
y
+
1.5
*
y
+
1.125
);
p.gy[
0
]
=
(y
+
1.5
);
y
+=
1.0
;
p.py[
1
]
=
(
-
y
*
y
+
0.75
);
p.gy[
1
]
=
(
-
2.0
*
y);
y
+=
1.0
;
p.py[
2
]
=
(
0.5
*
y
*
y
-
1.5
*
y
+
1.125
);
p.gy[
2
]
=
(y
-
1.5
);
for
(
int
i
=
0
; i
<
3
; i
++
)
{
for
(
int
j
=
0
; j
<
3
; j
++
)
{
Node n
=
this
.grid[p.cx
+
i][p.cy
+
j];
if
(
!
n.active)
{
this
.active.Add(n);
n.active
=
true
;
}
phi
=
p.px[i]
*
p.py[j];
n.m
+=
phi
*
p.mat.m;
n.d
+=
phi;
n.gx
+=
p.gx[i]
*
p.py[j];
n.gy
+=
p.px[i]
*
p.gy[j];
}
}
}
double
density, pressure, weight;
Node n01, n02;
Node n11, n12;
int
cx, cy;
int
cxi, cyi;
double
pdx, pdy;
double
C20, C02, C30, C03;
double
csum1, csum2;
double
C21, C31, C12, C13, C11;
double
u, u2, u3;
double
v, v2, v3;
foreach
(Particle p
in
this
.particles)
{
cx
=
(
int
)(p.x);
cy
=
(
int
)(p.y);
cxi
=
cx
+
1
;
cyi
=
cy
+
1
;
n01
=
this
.grid[cx][cy];
n02
=
this
.grid[cx][cyi];
n11
=
this
.grid[cxi][cy];
n12
=
this
.grid[cxi][cyi];
pdx
=
n11.d
-
n01.d;
pdy
=
n02.d
-
n01.d;
C20
=
3.0
*
pdx
-
n11.gx
-
2.0
*
n01.gx;
C02
=
3.0
*
pdy
-
n02.gy
-
2.0
*
n01.gy;
C30
=
-
2.0
*
pdx
+
n11.gx
+
n01.gx;
C03
=
-
2.0
*
pdy
+
n02.gy
+
n01.gy;
csum1
=
n01.d
+
n01.gy
+
C02
+
C03;
csum2
=
n01.d
+
n01.gx
+
C20
+
C30;
C21
=
3.0
*
n12.d
-
2.0
*
n02.gx
-
n12.gx
-
3.0
*
csum1
-
C20;
C31
=
-
2.0
*
n12.d
+
n02.gx
+
n12.gx
+
2.0
*
csum1
-
C30;
C12
=
3.0
*
n12.d
-
2.0
*
n11.gy
-
n12.gy
-
3.0
*
csum2
-
C02;
C13
=
-
2.0
*
n12.d
+
n11.gy
+
n12.gy
+
2.0
*
csum2
-
C03;
C11
=
n02.gx
-
C13
-
C12
-
n01.gx;
u
=
p.x
-
cx;
u2
=
u
*
u;
u3
=
u
*
u2;
v
=
p.y
-
cy;
v2
=
v
*
v;
v3
=
v
*
v2;
density
=
n01.d
+
n01.gx
*
u
+
n01.gy
*
v
+
C20
*
u2
+
C02
*
v2
+
C30
*
u3
+
C03
*
v3
+
C21
*
u2
*
v
+
C31
*
u3
*
v
+
C12
*
u
*
v2
+
C13
*
u
*
v3
+
C11
*
u
*
v;
pressure
=
density
-
1.0
;
if
(pressure
>
2.0
)
pressure
=
2.0
;
fx
=
0.0
;
fy
=
0.0
;
if
(p.x
<
4.0
)
fx
+=
p.mat.m
*
(
4.0
-
p.x);
else
if
(p.x
>
this
.gsizeX
-
5
)
fx
+=
p.mat.m
*
(
this
.gsizeX
-
5
-
p.x);
if
(p.y
<
4.0
)
fy
+=
p.mat.m
*
(
4.0
-
p.y);
else
if
(p.y
>
this
.gsizeY
-
5
)
fy
+=
p.mat.m
*
(
this
.gsizeY
-
5
-
p.y);
if
(drag)
{
var vx
=
Math.Abs(p.x
-
0.25
*
this
.mx);
var vy
=
Math.Abs(p.y
-
0.25
*
this
.my);
if
((vx
<
10.0
)
&&
(vy
<
10.0
))
{
weight
=
p.mat.m
*
(
1.0
-
vx
*
0.10
)
*
(
1.0
-
vy
*
0.10
);
fx
+=
weight
*
(mdx
-
p.u);
fy
+=
weight
*
(mdy
-
p.v);
}
}
for
(
int
i
=
0
; i
<
3
; i
++
)
{
for
(
int
j
=
0
; j
<
3
; j
++
)
{
Node n
=
this
.grid[(p.cx
+
i)][(p.cy
+
j)];
phi
=
p.px[i]
*
p.py[j];
n.ax
+=
-
((p.gx[i]
*
p.py[j])
*
pressure)
+
fx
*
phi;
n.ay
+=
-
((p.px[i]
*
p.gy[j])
*
pressure)
+
fy
*
phi;
}
}
}
foreach
(Node n
in
this
.active)
{
//
var n = this.active[ni];
if
(n.m
>
0.0
)
{
n.ax
/=
n.m;
n.ay
/=
n.m;
n.ay
+=
0.03
;
}
}
double
mu, mv;
foreach
(Particle p
in
this
.particles)
{
//
var p = this.particles[pi];
for
(
int
i
=
0
; i
<
3
; i
++
)
{
for
(
int
j
=
0
; j
<
3
; j
++
)
{
Node n
=
this
.grid[(p.cx
+
i)][(p.cy
+
j)];
phi
=
p.px[i]
*
p.py[j];
p.u
+=
phi
*
n.ax;
p.v
+=
phi
*
n.ay;
}
}
mu
=
p.mat.m
*
p.u;
mv
=
p.mat.m
*
p.v;
for
(
int
i
=
0
; i
<
3
; i
++
)
{
for
(
int
j
=
0
; j
<
3
; j
++
)
{
Node n
=
this
.grid[(p.cx
+
i)][(p.cy
+
j)];
phi
=
p.px[i]
*
p.py[j];
n.u
+=
phi
*
mu;
n.v
+=
phi
*
mv;
}
}
}
foreach
(Node n
in
this
.active)
{
//
var n = this.active[ni];
if
(n.m
>
0.0
)
{
n.u
/=
n.m;
n.v
/=
n.m;
}
}
double
gu, gv;
Random rm
=
new
Random();
foreach
(Particle p
in
this
.particles)
{
//
var p = this.particles[pi];
gu
=
0.0
;
gv
=
0.0
;
for
(var i
=
0
; i
<
3
; i
++
)
{
for
(var j
=
0
; j
<
3
; j
++
)
{
var n
=
this
.grid[(p.cx
+
i)][(p.cy
+
j)];
phi
=
p.px[i]
*
p.py[j];
gu
+=
phi
*
n.u;
gv
+=
phi
*
n.v;
}
}
p.x
+=
gu;
p.y
+=
gv;
p.u
+=
1.0
*
(gu
-
p.u);
p.v
+=
1.0
*
(gv
-
p.v);
if
(p.x
<
1.0
)
{
p.x
=
(
1.0
+
rm.Next(
0
,
1
)
*
0.01
);
p.u
=
0.0
;
}
else
if
(p.x
>
this
.gsizeX
-
2
)
{
p.x
=
(
this
.gsizeX
-
2
-
rm.Next(
0
,
1
)
*
0.01
);
p.u
=
0.0
;
}
if
(p.y
<
1.0
)
{
p.y
=
(
1.0
+
rm.Next(
0
,
1
)
*
0.01
);
p.v
=
0.0
;
}
else
if
(p.y
>
this
.gsizeY
-
2
)
{
p.y
=
(
this
.gsizeY
-
2
-
rm.Next(
0
,
1
)
*
0.01
);
p.v
=
0.0
;
}
}
}
}
private
void
line(
double
x1,
double
y1,
double
x2,
double
y2)
{
Path path
=
canvas.Children[
1
]
as
Path;
GeometryGroup aPathGeometry;
//
= new PathGeometry();
if
(path.Data
==
null
)
{
aPathGeometry
=
new
GeometryGroup();
path.Data
=
aPathGeometry;
path.Stroke
=
new
SolidColorBrush(Colors.Black);
path.StrokeThickness
=
2
;
}
else
{
aPathGeometry
=
path.Data
as
GeometryGroup;
}
LineGeometry Line
=
new
LineGeometry();
Line.StartPoint
=
new
Point(x1, y1);
Line.EndPoint
=
new
Point(x2, y2);
aPathGeometry.Children.Add(Line);
}
}
}