1
+ import numpy as np
2
+ import matplotlib .pyplot as plt
3
+ from scipy .ndimage import gaussian_filter
4
+
5
+ BOUNDS = 1024
6
+ FILTER_SIGMA = 12
7
+ FRAMES = 30
8
+ #np.random.seed(2)
9
+
10
+ class SimpleParticles ():
11
+ ''' Creates a grid filled with particles an a force field with gaussian blur applied to it
12
+ '''
13
+ def __init__ (self , bounds , filter_sigma ):
14
+ self .particleForceX_unblurred = np .random .random (size = [bounds ,bounds ])
15
+ self .particleForceX = gaussian_filter (self .particleForceX_unblurred , sigma = filter_sigma )
16
+ self .particleForceY_unblurred = np .random .random (size = [bounds ,bounds ])
17
+ self .particleForceY = gaussian_filter (self .particleForceY_unblurred , sigma = filter_sigma )
18
+ self .particles = (np .random .random (size = [bounds ,bounds ]) - 0.4 ).round ()
19
+
20
+ self .bounds = bounds
21
+ self .filter_sigma = filter_sigma
22
+
23
+ def change_force_field (self ):
24
+ # for x, particleRow in enumerate(self.particleForceX_unblurred):
25
+ # for y, particle in enumerate(particleRow):
26
+ # particle = 1 - particle
27
+ # self.particleForceX = gaussian_filter(self.particleForceX_unblurred, sigma=FILTER_SIGMA)
28
+ # with np.nditer(self.particleForceY_unblurred, op_flags=['readwrite']) as it:
29
+ # for y in it:
30
+ # y[...] = 1 - y
31
+ # self.particleForceY = gaussian_filter(self.particleForceY_unblurred, sigma=FILTER_SIGMA)
32
+ self .particleForceX_unblurred = np .random .random (size = [BOUNDS ,BOUNDS ])
33
+ self .particleForceX = gaussian_filter (self .particleForceX_unblurred , sigma = FILTER_SIGMA )
34
+ self .particleForceY_unblurred = np .random .random (size = [BOUNDS ,BOUNDS ])
35
+ self .particleForceY = gaussian_filter (self .particleForceY_unblurred , sigma = FILTER_SIGMA )
36
+
37
+ def move_particle (self , x , y , recursion = False ):
38
+ ''' Moves a particle according to the force exhibited by the force field.
39
+ If the destination is not free the function gets called recursively and "pushes" the particles forward along the force grid.
40
+ particle values:
41
+ * 1 -> normal value, not changed since last frame was rendered
42
+ * 1.2 -> value once the particle has changed position
43
+ * 1.3 -> value for loops within the system, no movement for this particles
44
+ '''
45
+ vector = self .get_force_vector (x , y )
46
+ particle_dest = [x + vector [0 ], y + vector [1 ]]
47
+ if particle_dest [0 ] > BOUNDS - 1 :
48
+ particle_dest [0 ] -= BOUNDS
49
+ if particle_dest [1 ] > BOUNDS - 1 :
50
+ particle_dest [1 ] -= BOUNDS
51
+
52
+ particle_dest_value = self .particles [particle_dest [0 ], particle_dest [1 ]]
53
+
54
+ if particle_dest_value == 1.2 :
55
+ self .particles [x , y ] = 1.2
56
+ return False
57
+
58
+ if particle_dest_value == 1 or particle_dest_value == 1.3 :
59
+ self .particles [x , y ] = 1.2
60
+ if self .move_particle (particle_dest [0 ], particle_dest [1 ], True ) is False :
61
+ self .particles [x , y ] = 1.2
62
+ return False
63
+
64
+ self .particles [x , y ] = 0
65
+ self .particles [particle_dest [0 ], particle_dest [1 ]] = 1.2 if recursion else 1.3
66
+
67
+ def get_force_vector (self , x , y ):
68
+ ''' Calculates the force vector based on the force grid.
69
+ '''
70
+ vector = [0 , 0 ]
71
+ if self .particleForceX [x , y ] > 0.5 :
72
+ vector [0 ] = 1
73
+ elif self .particleForceX [x , y ] <= 0.5 :
74
+ vector [0 ] = - 1
75
+ if self .particleForceY [x , y ] > 0.5 :
76
+ vector [1 ] = 1
77
+ elif self .particleForceY [x , y ] <= 0.5 :
78
+ vector [1 ] = - 1
79
+ return vector
80
+
81
+ def render (self , frames ):
82
+ ''' Renders the simulation and exports it into "./Export/".
83
+ '''
84
+ for i in range (frames ):
85
+ for x , particleRow in enumerate (self .particles ):
86
+ for y , particle in enumerate (particleRow ):
87
+ if particle != 0 and particle != 1.3 :
88
+ self .move_particle (x , y )
89
+
90
+ self .particles = self .particles .round ()
91
+ plt .imshow (self .particles )
92
+ ax = plt .gca ()
93
+ ax .get_yaxis ().set_visible (False )
94
+ ax .get_xaxis ().set_visible (False )
95
+ plt .savefig (fname = f"./Export/Frame-{ i } " )
96
+ print (f"Done with Frame { i } " )
97
+ if i % 5 == 0 :
98
+ self .change_force_field ()
99
+
100
+ if __name__ == "__main__" :
101
+ particles = SimpleParticles (BOUNDS , FILTER_SIGMA )
102
+ particles .render (FRAMES )
0 commit comments