From d2fd778fbc91162f583b0b9b38a29e7fb893743d Mon Sep 17 00:00:00 2001 From: Looki2000 Date: Sun, 21 May 2023 01:08:22 +0200 Subject: [PATCH] added cursor force and more other changes --- .vscode/launch.json | 16 +++++++++++ gas_sim.py | 35 ++++++++++++++++++------ main.py | 65 +++++++++++++++++++++++--------------------- particles.npy | Bin 5632 -> 7744 bytes 4 files changed, 76 insertions(+), 40 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9ebed2f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: main file", + "type": "python", + "request": "launch", + "program": "main.py", + "console": "integratedTerminal", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/gas_sim.py b/gas_sim.py index 5f1c567..aa28c0a 100644 --- a/gas_sim.py +++ b/gas_sim.py @@ -2,22 +2,39 @@ from math import hypot class GasSim: - def __init__(self, particle_radius, particle_compressibility, particle_friction, substeps): + def __init__(self, particle_radius, particle_compressibility, particle_friction, substeps, window_aspect): self.particle_radius = particle_radius self.particle_compressibility = particle_compressibility self.particle_friction = particle_friction self.substeps = substeps + self.window_aspect = window_aspect + self.particles = [] - self.walls = [] - def add_particle(self, pos, vel = (0, 0)): - self.particles.append([pos, vel]) + def add_particle(self, pos, vel = [0, 0]): + self.particles.append([list(pos).copy(), vel.copy()]) - def cursor_particle_collide_test(self, cursor_pos, cursor_radius): + def circle_particle_collide_test(self, pos, radius): for particle in self.particles: - if hypot(particle[0][0] - cursor_pos[0], particle[0][1] - cursor_pos[1]) <= cursor_radius + self.particle_radius: + if hypot(particle[0][0] - pos[0], particle[0][1] - pos[1]) <= radius + self.particle_radius: return True - - def add_wall(self, start, end): - self.walls.append((start, end)) \ No newline at end of file + + def circle_force(self, pos, radius, vector, dt): + for i, particle in enumerate(self.particles): + if hypot(particle[0][0] - pos[0], particle[0][1] - pos[1]) <= radius + self.particle_radius: + self.particles[i][1][0] += vector[0] * dt + self.particles[i][1][1] += vector[1] * dt + + def update(self, dt): + # substeps + for _ in range(self.substeps): + # update particles + for i, particle in enumerate(self.particles): + + # + + + # position + self.particles[i][0][0] += particle[1][0] * dt / self.substeps + self.particles[i][0][1] += particle[1][1] * dt / self.substeps \ No newline at end of file diff --git a/main.py b/main.py index 617eac1..158192f 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,7 @@ import pygame import pygame.gfxdraw import gas_sim as gs import numpy as np +import random ##### CONFIG ##### window_size = (1280, 720) @@ -32,21 +33,13 @@ clock = pygame.time.Clock() # gas sim init -gas_sim = gs.GasSim(particle_radius_ws, particle_compressibility, particle_friction, substeps) - - -# add walls -gas_sim.add_wall((0, 0), (window_aspect, 0)) -gas_sim.add_wall((0, 1), (window_aspect, 1)) -gas_sim.add_wall((0, 0), (0, 1)) -gas_sim.add_wall((1, 0), (1, 1)) +gas_sim = gs.GasSim(particle_radius_ws, particle_compressibility, particle_friction, substeps, window_aspect) not_loaded_particles = True dt = target_fps / 1000 - # main loop while True: # events @@ -55,8 +48,31 @@ while True: pygame.quit() quit() + elif event.type == pygame.KEYDOWN: + # on s key press + if event.key == pygame.K_s: + # save particles to file + particles = tuple(pos for pos, _ in gas_sim.particles) + np.save("particles.npy", particles) - # on mouse down + print("Saved particles to file") + + # on l key press + elif event.key == pygame.K_l: + if not_loaded_particles: + # load particles from file + particles = np.load("particles.npy") + for particle in particles: + gas_sim.add_particle(particle) + + print("Loaded particles from file") + + not_loaded_particles = False + else: + print("Particles already loaded !!!") + + + # on left mouse down if pygame.mouse.get_pressed()[0]: mouse_pos_ss = pygame.mouse.get_pos() @@ -64,33 +80,20 @@ while True: mouse_pos_ws = (mouse_pos_ss[0] / window_size[1], mouse_pos_ss[1] / window_size[1]) # if not colliding with any particles - if not gas_sim.cursor_particle_collide_test(mouse_pos_ws, particle_radius_ws): + if not gas_sim.circle_particle_collide_test(mouse_pos_ws, particle_radius_ws): gas_sim.add_particle(mouse_pos_ws) - - # on s key press - if pygame.key.get_pressed()[pygame.K_s]: - # save particles to file - particles = tuple(pos for pos, _ in gas_sim.particles) - np.save("particles.npy", particles) - - print("Saved particles to file") - # on l key press - if not_loaded_particles and pygame.key.get_pressed()[pygame.K_l]: - # load particles from file - particles = np.load("particles.npy") - for particle in particles: - gas_sim.add_particle(particle) - - print("Loaded particles from file") - - not_loaded_particles = False + # on right mouse down + elif pygame.mouse.get_pressed()[2]: + # apply wind force + mouse_pos_ss = pygame.mouse.get_pos() + mouse_pos_ws = (mouse_pos_ss[0] / window_size[1], mouse_pos_ss[1] / window_size[1]) + gas_sim.circle_force(mouse_pos_ws, cursor_radius_ws, (0.2, random.uniform(-0.5, 0.5)), dt) # update particles - #gas_sim.update(dt) - + gas_sim.update(dt) diff --git a/particles.npy b/particles.npy index cf35a8fb197375c7a4f4f5cc37b13e5e66517842..5bb9c8713fb03f8af0ad098e1f0a954d1c4c06b4 100644 GIT binary patch literal 7744 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 literal 5632 zcmbW5OKenS6vuI)3t73r4U5K2F##9Cq8h`uF(#O(Y*-i;(nuQ@M6?)PC>z-5h7B%2 zLRf&Hk|4wcLV)sWpa_(CGfJ=icx8&N=_{KaV>{ zKi>7x&QD)j_wBmx`}YnV_W4F$~#@%cF6>uBxf8G6!x!W7|b$|1& zedd$y?+*86_s$V-;D~q2)pne!?l={5%S*lMhWpOH60W!F_J-^3eg8_k-4|c({;oOE zmowRAj&9E!EtvdkPffdM^5HGPLtBDnlLyyd-n0I4)nwUUH(Bg%nk?(vFUTE}Wqrr} z+_hqR=B|6iH?-}1_cz{mJ?)3KwA@cW_O5aFy6;%SWLZ~d-MHK8UsaO@zg72P52oq^ zC-!7ryo=tzk%#C_IPv=t&!gb^*!eIIEI9FV0=#G3YN2;cxL=ORUi=WRqcLx4Eb8q<9EOvEF7CYJ|OWd0HI}4sw{0%riEIZ2h8{mCW;NBiE zz6#%Guq%!KGsMfYxClR%O@92ScLm+S>Hh97;QZUcX|qT25gXkM)--6re zC*l)$7BW4;-w^xf;pZZG9C2dDBE0rY79J#7w}{^v@;C%PbMSA$_@H$`_*`UvkoeXN zf2jj?=cnzSIVbsC2frXZY2bed{~F}kvaOf;5oKMCJdJ{5h58l4uM*E=*i|I1F*o7^ zyFy)x;b+cdiE|peV(?D!iIE>3c*Ja<;1C1%2zJNFmnH5V`saz?f4mWVJd3a7foFAj zlTRRx+ZcEzIClzurQmA-J5$`}!8=Vn!|c~Md*pEjTocs&417wFXKDDD#m_YO=1t%E zKYCYz^Hca)=9~mPuE4VdI97>w96s0Fuz$tL%Lcf4Ja6*cgKsVD^}wNxe$R357oJTK*8+TgWamr$9W`0%>qV2Lp9JAUp1v9; zE_sWi%e&WuA+`Go4o=#Ia1>i%>U;@H&jYE9STGBMpvW;u|1N zVd5}FoelH+A%2CyB|?5^|Im6nWA$6-3+b;F{FyNSrH|=6R09W{PgXep5qY3^-@~3L z@5k_W5*%((UvGo^D0p2oS?n1mA4bvp+fA9ni?SfFCvT=sf;6 z!09Y?L+jOPaMbzs1om~{&oOwb^Vc!-Xnvd|-z)fk27I)Cp5=Yf^vgW2b>=Ml^7dYM zl{H!B>6FRR{}unU;HG`}9C;W4w{z5y1^UzPIA8s_XL%xi|IPd{X?K|?#<6=EJEEKuAl@Z-Jj;0%p3lOk zGP3S3)9)To7fRT9mwr(uA4AN073z&=vh(M&zz)vR_Eq4aY%wo(&~@QfeCmL#D3*Z4t&EF7vbL$cukStGn|*9 zUft%LEdJiW{xo=A#lHk`xNP&M^tDUm+amEeihbkAhi}UF^+ode2j0(s=W+B#$@>%N z^QfOEd7r?)Q`Uc^|DK^9rQ!D_@>uzDpXV9k`UF3U#w(d4%Gmpq=N0PIQ|u}kj?zDK ztiOx@FRac+TqP3$aiud^@Dc{Spm z!w&ubL%&mMJlFZW4nK5$RsCt|R)_P`*wH3lS?Y%Nhb(xlkf&Mrue{Umz@q7wIj)M` zIe6FN9Q~i?nVl!~P`}@^*i)y@Wy#wtan6xv0qR!{KbMGSn)UksQ3kzp^wlVJK8l|S zt0VF~u5!roOaAv*g6|>AYw>dqeL?J-BF?k$eGVKv^v`ooasCwX(C;RlNAl$JBoWL+u&ahWA$VTLt^_z&*spVHm3q5KeXLMVrtw$5cXXa@Qn%ya z*)cz5zFf0>lK&+-_CJaKzb5q~%DxVLK8C$*>PUzLCCC