Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
particle_system.hpp
Go to the documentation of this file.
1
5#ifndef PARTICLE_SYSTEM_H
6#define PARTICLE_SYSTEM_H
7
8#include <cstdint>
9#include <functional>
10#include <set>
11
12#include "src/system/ext/random8.h"
13
15
16#include "particle.hpp"
17
18namespace lampda::modes {
19
20using LampTy = hardware::LampTy;
21
27{
28public:
29 ParticleSystem() : particuleCount(0) { reset(); }
30
34 void reset()
35 {
36 occupiedSpacesSet.clear();
37 for (size_t i = 0; i < ParticleSystem::maxParticuleCount; ++i)
38 {
39 isAllocated[i] = false;
40 }
41 }
42
47 void set_max_particle_count(const uint16_t _particleCount)
48 {
49 particuleCount = std::min<uint16_t>(ParticleSystem::maxParticuleCount, _particleCount);
50 reset();
51 }
52
57 void init_particules(const std::function<int16_t(size_t)>& positionGeneratorFunction)
58 {
59 occupiedSpacesSet.clear();
60 for (size_t i = 0; i < particuleCount; ++i)
61 {
62 isAllocated[i] = false;
63 spawn_particule(i, positionGeneratorFunction);
64 }
65 }
66
72 void init_deferred_particules(uint8_t maxParticlesToPop,
73 const std::function<int16_t(size_t)>& positionGeneratorFunction)
74 {
75 for (size_t i = 0; i < particuleCount and maxParticlesToPop > 0; ++i)
76 {
77 if (isAllocated[i])
78 {
79 // already allocated, do not reuse
80 continue;
81 }
82 spawn_particule(i, positionGeneratorFunction);
83 maxParticlesToPop--;
84 }
85 }
86
93 void iterate_no_collisions(const utils::vec3d& accelerationCartesian,
94 const float deltaTime_s,
95 const bool shouldContrain = true)
96 {
97 for (size_t i = 0; i < particuleCount; ++i)
98 {
99 // do not iterate non allocated particles
100 if (not isAllocated[i])
101 continue;
102
103 Particle& p = particules[i];
104 // apply force and constrain
105 p.apply_acceleration(accelerationCartesian, deltaTime_s, shouldContrain);
106 }
107 }
108
115 void iterate_with_collisions(const utils::vec3d& accelerationCartesian,
116 const float deltaTime_s,
117 const bool shouldContrain = true)
118 {
119 for (size_t i = 0; i < particuleCount; ++i)
120 {
121 // do not iterate non allocated particles
122 if (not isAllocated[i])
123 continue;
124
125 Particle& p = particules[i];
126 const int16_t ledIndex = p._savedLampIndex;
127
128 // simulate instead of updating directly
129 const Particle& newP = p.simulate_after_acceleration(accelerationCartesian, deltaTime_s, shouldContrain);
130
131 // update particle position in occupation set
132 const int16_t newLedIndex = newP._savedLampIndex;
133 if (newLedIndex != ledIndex)
134 {
135 // check collision : no collision
136 if (not is_position_taken(newLedIndex))
137 {
138 occupiedSpacesSet.erase(ledIndex);
139 occupiedSpacesSet.insert(newLedIndex);
140 }
141 // check collision : collision !!
142 else
143 {
144 // refuse movement, rebound speed
145 p.thetaSpeed_radS = -p.thetaSpeed_radS * 0.75;
146 p.zSpeed_mS = -p.zSpeed_mS * 0.75;
147 continue;
148 }
149 }
150
151 // update particle
152 p = newP;
153 }
154 }
155
162 uint16_t depop_particules(const std::function<bool(const Particle&)>& shouldDepopFunction)
163 {
164 uint16_t particleCount = 0;
165 for (size_t i = 0; i < particuleCount; ++i)
166 {
167 // do not depop non allocated particles
168 if (not isAllocated[i])
169 continue;
170
171 auto& parti = particules[i];
172 if (shouldDepopFunction(parti))
173 {
174 isAllocated[i] = false;
175 occupiedSpacesSet.erase(parti._savedLampIndex);
176 }
177 else
178 {
179 particleCount += 1;
180 }
181 }
182 return particleCount;
183 }
184
190 uint16_t show(const std::function<uint32_t(int16_t, const Particle&)> sample_color, LampTy& lamp)
191 {
192 uint16_t particleCount = 0;
193 for (size_t i = 0; i < particuleCount; ++i)
194 {
195 // do not show non allocated particles
196 if (not isAllocated[i])
197 continue;
198 const auto& particle = particules[i];
199 const auto& index = particle._savedLampIndex;
200 if (modes::is_led_index_valid(index))
201 lamp.setPixelColor(index, sample_color(i, particle));
202 else
203 particleCount += 1;
204 }
205 return particleCount;
206 }
207
209 uint16_t get_number_of_active() const
210 {
211 uint16_t particleCount = 0;
212 for (size_t i = 0; i < particuleCount; ++i)
213 {
214 // do not show non allocated particles
215 if (not isAllocated[i])
216 continue;
217 particleCount += 1;
218 }
219 return particleCount;
220 }
221
222protected:
224 bool is_position_taken(const int16_t pos) const { return occupiedSpacesSet.find(pos) != occupiedSpacesSet.cend(); }
225
231 void spawn_particule(const size_t index, const std::function<int16_t(size_t)>& positionGeneratorFunction)
232 {
233 int16_t pos = positionGeneratorFunction(index);
234 int maxTries = 3;
235 while (ParticleSystem::is_position_taken(pos) and maxTries > 0)
236 {
237 pos = positionGeneratorFunction(index);
238 maxTries--;
239 }
240 // generate start position from user function
241 const auto& helixCoordinates = modes::strip_to_helix_unconstraint(pos);
242 particules[index] = Particle(utils::vec3d {helixCoordinates.x, helixCoordinates.y, helixCoordinates.z});
243 occupiedSpacesSet.insert(pos);
244 isAllocated[index] = true;
245 }
246
247private:
248 static constexpr uint16_t maxParticuleCount = 512;
249 Particle particules[maxParticuleCount];
250 bool isAllocated[maxParticuleCount];
251
252 std::set<int16_t> occupiedSpacesSet;
253
255 uint16_t particuleCount;
256};
257
258} // namespace lampda::modes
259
260#endif
Define a particle system ALL PARTICLE SYSTEM SHARE THE SAME PÄRTICLE SUBSET.
Definition: particle_system.hpp:27
void spawn_particule(const size_t index, const std::function< int16_t(size_t)> &positionGeneratorFunction)
Spawn a particle.
Definition: particle_system.hpp:231
uint16_t get_number_of_active() const
Return the number of active particles.
Definition: particle_system.hpp:209
uint16_t show(const std::function< uint32_t(int16_t, const Particle &)> sample_color, LampTy &lamp)
Display this particle system.
Definition: particle_system.hpp:190
bool is_position_taken(const int16_t pos) const
Return True if the position is already occupied.
Definition: particle_system.hpp:224
void iterate_no_collisions(const utils::vec3d &accelerationCartesian, const float deltaTime_s, const bool shouldContrain=true)
Advance the particle simulation, ignoring collisions.
Definition: particle_system.hpp:93
void set_max_particle_count(const uint16_t _particleCount)
Call when you want to change the particle count of the simulation Can be called once when starting th...
Definition: particle_system.hpp:47
uint16_t depop_particules(const std::function< bool(const Particle &)> &shouldDepopFunction)
Filter particles depending on condition.
Definition: particle_system.hpp:162
void init_deferred_particules(uint8_t maxParticlesToPop, const std::function< int16_t(size_t)> &positionGeneratorFunction)
Init the particles from a initialization function, in a timed defered way.
Definition: particle_system.hpp:72
void init_particules(const std::function< int16_t(size_t)> &positionGeneratorFunction)
Init the particles from a initialization function.
Definition: particle_system.hpp:57
void reset()
reset system to zero count
Definition: particle_system.hpp:34
void iterate_with_collisions(const utils::vec3d &accelerationCartesian, const float deltaTime_s, const bool shouldContrain=true)
Advance the particle simulation, taking collisions in account.
Definition: particle_system.hpp:115
Define the main led strip interaction object.
Contains basic interface types to implement custom user modes.
Definition: control_fixed_modes.hpp:12
hardware::LampTy LampTy
Define a particle in cylindrical space, and movement equations on the cylinder surface.
Definition: particle.hpp:22
static constexpr bool is_led_index_valid(const int16_t ledIndex)
True if the given strip index is a valid one.
Definition: lamp_type.hpp:1189
static constexpr HelixXYZTy strip_to_helix_unconstraint(const int16_t n)
convert strip index to 3D coordinates, without checks on led index. This allows to use 3D coordinates...
Definition: lamp_type.hpp:1178
Define a single particle for a particle system.
Define a particle in 3D space. it has a position and speed.
Definition: particle.hpp:37
void apply_acceleration(const utils::vec3d &accelerationCartesian_m, const float deltaTime_s, const bool shouldContrain=true)
apply a cartesian acceleration to this particulate
Definition: particle.hpp:94
int16_t _savedLampIndex
optimization
Definition: particle.hpp:207
Particle simulate_after_acceleration(const utils::vec3d &accelerationCartesian_m, const float deltaTime_s, const bool shouldContrain=true) const
Simulate this particle movement as a new particle.
Definition: particle.hpp:136
float thetaSpeed_radS
angular speed, in radian/seconds
Definition: particle.hpp:200
float zSpeed_mS
linear speed, in meter/seconds
Definition: particle.hpp:201
Main interface between the user and the hardware of the lamp.
Definition: lamp_type.hpp:114
void LMBD_INLINE setPixelColor(uint16_t n, uint32_t color)
(indexable) Set the n-th LED color
Definition: lamp_type.hpp:874
float x
x coordinate in 2D
Definition: vector_math.h:16
3d vector in any space
Definition: vector_math.h:54