CellModules
PluginDelaunayMassSpringDamper.hpp
Go to the documentation of this file.
1#ifndef PLUGINBODYDELAUNAYMASSSPRINGDAMPER_HPP
2#define PLUGINBODYDELAUNAYMASSSPRINGDAMPER_HPP
3
11#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
12#include <CGAL/Delaunay_triangulation_3.h>
13#include <CGAL/Triangulation_vertex_base_with_info_3.h>
14#include <vector>
15#include <mecacell/mecacell.h>
16#include "MassSpringDamper.hpp"
17
18using K = CGAL::Exact_predicates_inexact_constructions_kernel;
19using Vb = CGAL::Triangulation_vertex_base_with_info_3<void *, K>;
20using Tds = CGAL::Triangulation_data_structure_3<Vb>;
21using Delaunay = CGAL::Delaunay_triangulation_3<K, Tds>;
23
29
36 template<typename cell_t>
38
39 private:
44 double physicsDt = 0.01;
45 double maxSpeed = 10.0;
46 double minForce = 1.0;
47 double neighbourCoeff = 1.1;
48 double coherenceCoeff = 0.2;
55 bool coherence = true;
56
57 if (triangulation.number_of_vertices() > 0) {
58
59 typename Delaunay::Finite_vertices_iterator vit;
60
61 for (vit = triangulation.finite_vertices_begin(); vit != triangulation.finite_vertices_end(); ++vit) { // For each vertex
62 cell_t *c = static_cast<cell_t *>(vit->info());
63 MecaCell::Vec pos = MecaCell::Vec(vit->point().x(), vit->point().y(), vit->point().z());
64 if ((c->getBody().getPosition() - pos).length()
65 >= c->getBody().getBoundingBoxRadius() * coherenceCoeff) { // Verify the coherence between the real position of a cell and its position in the triangulation
66 coherence = false;
67 break;
68 }
69 }
70 } else coherence = false;
71 return coherence;
72 }
73
77 void moveDelaunay() {
78 typename Delaunay::Finite_vertices_iterator vit;
79 vit = triangulation.finite_vertices_begin();
80 for (int i = 0; i < triangulation.number_of_vertices(); ++i) { // For each vertex
81 cell_t *c = static_cast<cell_t *>(vit->info());
82 c->clearConnectedCells();
83 MecaCell::Vec pos = MecaCell::Vec(vit->point().x(), vit->point().y(), vit->point().z());
84 if ((c->getBody().getPosition() - pos).length()
85 >= c->getBody().getBoundingBoxRadius() * coherenceCoeff) { // Verify the coherence between the real position of a cell and its position in the triangulation
86 Point p(c->getBody().getPosition().x(), c->getBody().getPosition().y(), c->getBody().getPosition().z());
87 triangulation.move(vit, p);
88 }
89 ++vit;
90 }
91 }
92
99 template<typename world_t>
100 void computeDelaunay(world_t *w) {
101 for (cell_t *c : w->cells) c->clearConnectedCells();
102 if (!isDelaunayCoherent()) {
103 std::vector<Point> points;
104 std::vector<void *> indices;
105 for (cell_t *c : w->cells) {
106 c->clearConnectedCells();
107
108 points.push_back(Point(c->getBody().getPosition().x(), c->getBody().getPosition().y(),
109 c->getBody().getPosition().z()));
110 indices.push_back(c);
111 }
112
113 triangulation.clear();
114 triangulation = Delaunay(boost::make_zip_iterator(boost::make_tuple(points.begin(), indices.begin())),
115 boost::make_zip_iterator(boost::make_tuple(points.end(), indices.end())));
116 }
117 }
118
123 if (!triangulation.is_valid()) {
124 std::cout << "UNVALID DELAUNAY !!" << std::endl;
125 }
126
128 typename Delaunay::Finite_edges_iterator eit;
129
130 for (eit = triangulation.finite_edges_begin(); eit != triangulation.finite_edges_end(); ++eit) { // For each spring
131 cell_t *c1 = static_cast<cell_t *>(eit->first->vertex(eit->second)->info());
132 cell_t *c2 = static_cast<cell_t *>(eit->first->vertex(eit->third)->info());
133 if (c1 != nullptr && c2 != nullptr) {
134 if ((c1->getBody().getPosition() - c2->getBody().getPosition()).length() <=
135 (c1->getBody().getBoundingBoxRadius() + c2->getBody().getBoundingBoxRadius()) * neighbourCoeff) { // Max distance to consider 2 neighbour cells
136 float_t r = 1.0; // Damping
137 float_t k = 10 * (c1->getBody().getMass() + c2->getBody().getMass()) / 2; // Stiffness proportional to the mass of the cells
138 float_t l = c1->getBody().getBoundingBoxRadius() * c1->getBody().getAdhesion() + c2->getBody().getBoundingBoxRadius() * c2->getBody().getAdhesion(); // Rest length
139 float_t c = r * 2.0 * sqrt((c1->getBody().getMass() + c2->getBody().getMass()) * k); // Damping coefficient
140
142 c1->addConnectedCell(c2);
143 c2->addConnectedCell(c1);
144 }
145 } else {
146 exit(41);
147 }
148 }
149 }
150
157 template<typename world_t>
158 void addCells(world_t *w) {
159 std::vector<Point> points;
160 std::vector<void *> indices;
161 for (cell_t *c : w->newCells) {
162 points.push_back(Point(c->getBody().getPosition().x(), c->getBody().getPosition().y(), c->getBody().getPosition().z()));
163 indices.push_back(c);
164 }
165
166 triangulation.insert(boost::make_zip_iterator(boost::make_tuple(points.begin(), indices.begin())),
167 boost::make_zip_iterator(boost::make_tuple(points.end(), indices.end())));
168 }
169
173 void removeCells() {
174 typename Delaunay::Finite_vertices_iterator vit;
175
176 for (vit = triangulation.finite_vertices_begin(); vit != triangulation.finite_vertices_end(); ++vit) { // For each vertex
177 auto *c1 = static_cast<cell_t *>(vit->info());
178
179 if (c1->isDead()) {
180 triangulation.remove(vit);
181 }
182 }
183 }
184
189 areForcesNegligible = true;
190 for (auto &msd : springList) {
191 msd.computeForces();
193 (msd.getConnection().first->getBody().getForce().length() > minForce || msd.getConnection().second->getBody().getForce().length() > minForce))
194 areForcesNegligible = false;
195 }
196 }
197
204 template<typename world_t>
205 void updatePositions(world_t *w) {
207 for (cell_t *c : w->cells) {
208 MecaCell::Vector3D vel = c->getBody().getVelocity() + c->getBody().getForce() * physicsDt / c->getBody().getMass();
209 if (vel.length() < maxSpeed) c->getBody().setVelocity(vel);
210 else c->getBody().setVelocity(maxSpeed * vel / vel.length());
211 c->getBody().setPrevposition(c->getBody().getPosition());
212 c->getBody().setPosition(c->getBody().getPosition() + c->getBody().getVelocity() * physicsDt);
213 if (areMovementsNegligible && vel.length() > coherenceCoeff * c->getBody().getBoundingBoxRadius())
215 }
216 }
217
224 template<typename world_t>
225 inline void resetForces(world_t *w) {
226 for (cell_t *c : w->cells) {
227 c->getBody().resetForce();
228 }
229 }
230
240 template<typename world_t>
241 void applyPhysics(world_t *w) {
242 double numberOfSteps = w->dt / physicsDt;
243 for (unsigned i = 0; i < numberOfSteps; i++) {
244 resetForces(w);
245 updateForces();
246 if (areForcesNegligible) break;
248 if (areMovementsNegligible) break;
249 }
250 }
251
252 public:
259
264 inline void setPhysicsDt(double dt) { physicsDt = dt; }
265
270 inline void setCoherenceCoeff(double c) { coherenceCoeff = c; }
271
276 inline void setMaxSpeed(double s) { maxSpeed = s; }
277
282 inline void setMinForce(double f) { minForce = f; }
283
288 inline void setNeighbourCoeff(double c) { neighbourCoeff = c; }
289
298 template<typename world_t>
299 void endUpdate(world_t *w) {
300 moveDelaunay();
302 }
303
312 template<typename world_t>
313 void onAddCell(world_t *w) {
314 addCells(w);
315 }
316
325 template<typename world_t>
326 void preBehaviorUpdate(world_t *w) {
327 applyPhysics(w);
328 }
329
338 template<typename world_t>
339 void preDeleteDeadCellsUpdate(world_t *w) {
340 for (cell_t *c : w->cells) {
341 if (c->isDead()) {
342 removeCells();
343 break;
344 }
345 }
346 }
347 };
348}
349
350#endif // PLUGINBODYDELAUNAYMASSSPRINGDAMPER_HPP
MecaCell::Vec pos
Definition: CellBody.hpp:34
Defines the MassSpringDamper class for mass-spring-damper physics.
Delaunay::Point Point
CGAL::Delaunay_triangulation_3< K, Tds > Delaunay
Delaunay::Point Point
CGAL::Delaunay_triangulation_3< K, Tds > Delaunay
CGAL::Triangulation_vertex_base_with_info_3< void *, K > Vb
CGAL::Triangulation_data_structure_3< Vb > Tds
CGAL::Exact_predicates_inexact_constructions_kernel K
Class for managing Delaunay triangulation and mass-spring-damper physics.
void applyPhysics(world_t *w)
Applies the physics with a coherent time step.
void moveDelaunay()
Moves the points in the triangulation to match their real positions.
void updateForces()
Updates forces and checks if the forces are too weak to be considered.
void updatePositions(world_t *w)
Updates positions and checks if the movements are too weak to be considered.
void preDeleteDeadCellsUpdate(world_t *w)
Pre-delete dead cells update hook for MecaCell.
bool isDelaunayCoherent()
Checks the coherence of the Delaunay triangulation.
void removeCells()
Removes dead cells from the triangulation.
void preBehaviorUpdate(world_t *w)
Pre-behavior update hook for MecaCell.
void computeDelaunay(world_t *w)
Computes the Delaunay triangulation from the list of cells.
void addCells(world_t *w)
Adds new cells to the triangulation.
void resetForces(world_t *w)
Resets the forces acting on the cells.
Class for managing mass-spring-damper physics.
general purpose 3D vector/point class.
Definition: vector3D.h:20
double length() const
compute the length of the vector
Definition: vector3D.h:257
A simple vector class template.
Definition: std.hpp:290
void push_back(const T &value)
Adds an element to the end of the vector.
Definition: std.hpp:304
iterator begin()
Returns an iterator to the first element.
Definition: std.hpp:409
void clear()
Clears the contents of the vector.
Definition: std.hpp:354
iterator end()
Returns an iterator to the last element.
Definition: std.hpp:418
Namespace for Delaunay triangulation and mass-spring-based physics-related classes and functions.
Vector3D Vec
alias for Vector3D
Definition: utils.hpp:22
iostream cout
Standard output stream.
Definition: std.hpp:267
double sqrt(double x)
Computes the square root of a number.
Definition: std.hpp:32
iostream endl
End-of-line manipulator.
Definition: std.hpp:274