1#ifndef PLUGINBODYHERTZIANPHYSICS_HPP
2#define PLUGINBODYHERTZIANPHYSICS_HPP
18#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
19#include <CGAL/Delaunay_triangulation_3.h>
20#include <CGAL/Triangulation_vertex_base_with_info_3.h>
22using K = CGAL::Exact_predicates_inexact_constructions_kernel;
23using Vb = CGAL::Triangulation_vertex_base_with_info_3<void *, K>;
24using Tds = CGAL::Triangulation_data_structure_3<Vb>;
25using Delaunay = CGAL::Delaunay_triangulation_3<K, Tds>;
40 template<
typename cell_t>
59 bool coherence =
true;
63 typename Delaunay::Finite_vertices_iterator vit;
68 cell_t *c =
static_cast<cell_t *
>(vit->info());
70 tolerance *= tolerance;
71 if ((c->getBody().getPosition().x() * vit->point().x() +
72 c->getBody().getPosition().y() * vit->point().y() +
73 c->getBody().getPosition().z() * vit->point().z())
79 }
else coherence =
false;
87 typename Delaunay::Finite_vertices_iterator vit;
90 for (
int i = 0; i <
triangulation.number_of_vertices(); ++i) {
91 cell_t *c =
static_cast<cell_t *
>(vit->info());
93 tolerance *= tolerance;
94 if ((c->getBody().getPosition().x() * vit->point().x() +
95 c->getBody().getPosition().y() * vit->point().y() +
96 c->getBody().getPosition().z() * vit->point().z())
98 Point p(c->getBody().getPosition().x(), c->getBody().getPosition().y(),
99 c->getBody().getPosition().z());
112 template<
typename world_t>
114 for (cell_t *c : w->cells) c->clearConnectedCells();
117 points.
reserve(w->cells.size());
118 for (cell_t *c : w->cells) points.
push_back(
Point(c->getBody().getPosition().x(), c->getBody().getPosition().y(), c->getBody().getPosition().z()));
122 boost::make_zip_iterator(boost::make_tuple(points.
end(), w->cells.end())));
132 template<
typename world_t>
135 points.
reserve(w->newCells.size());
136 for (cell_t *c : w->newCells) points.
push_back(
Point(c->getBody().getPosition().x(), c->getBody().getPosition().y(), c->getBody().getPosition().z()));
138 triangulation.insert(boost::make_zip_iterator(boost::make_tuple(points.
begin(), w->newCells.begin())),
139 boost::make_zip_iterator(boost::make_tuple(points.
end(), w->newCells.end())));
146 typename Delaunay::Finite_vertices_iterator vit;
150 auto *c1 =
static_cast<cell_t *
>(vit->info());
164 template<
typename world_t>
169 for (
auto c : w->cells) c->clearConnectedCells();
171 typename Delaunay::Finite_edges_iterator eit;
175 cell_t *c1 =
static_cast<cell_t *
>(eit->first->vertex(eit->second)->info());
176 cell_t *c2 =
static_cast<cell_t *
>(eit->first->vertex(eit->third)->info());
177 if (c1 !=
nullptr && c2 !=
nullptr) {
178 double maxdist = c1->getBody().getBoundingBoxRadius() + c2->getBody().getBoundingBoxRadius();
179 if ((c1->getBody().getPosition() - c2->getBody().getPosition()).sqlength() <=
181 c1->addConnectedCell(c2);
182 c2->addConnectedCell(c1);
196 template<
typename world_t>
198 for (
auto c : w->cells) {
199 double minConstX =
minConstraint.
x() + c->getBody().getBoundingBoxRadius();
200 double minConstY =
minConstraint.
y() + c->getBody().getBoundingBoxRadius();
201 double minConstZ =
minConstraint.
z() + c->getBody().getBoundingBoxRadius();
203 double maxConstX =
maxConstraint.
x() - c->getBody().getBoundingBoxRadius();
204 double maxConstZ =
maxConstraint.
z() - c->getBody().getBoundingBoxRadius();
205 double maxConstY =
maxConstraint.
y() - c->getBody().getBoundingBoxRadius();
207 if (c->getBody().getPosition().x() < minConstX) {
208 c->getBody().setPosition(
209 MecaCell::Vec(minConstX, c->getBody().getPosition().y(), c->getBody().getPosition().z()));
210 }
else if (c->getBody().getPosition().x() > maxConstX) {
211 c->getBody().setPosition(
212 MecaCell::Vec(maxConstX, c->getBody().getPosition().y(), c->getBody().getPosition().z()));
214 if (c->getBody().getPosition().y() < minConstY) {
215 c->getBody().setPosition(
216 MecaCell::Vec(c->getBody().getPosition().x(), minConstY, c->getBody().getPosition().z()));
217 }
else if (c->getBody().getPosition().y() > maxConstY) {
218 c->getBody().setPosition(
219 MecaCell::Vec(c->getBody().getPosition().x(), maxConstY, c->getBody().getPosition().z()));
221 if (c->getBody().getPosition().z() < minConstZ) {
222 c->getBody().setPosition(
223 MecaCell::Vec(c->getBody().getPosition().x(), c->getBody().getPosition().y(), minConstZ));
224 }
else if (c->getBody().getPosition().z() > maxConstZ) {
225 c->getBody().setPosition(
226 MecaCell::Vec(c->getBody().getPosition().x(), c->getBody().getPosition().y(), maxConstZ));
238 template<
typename world_t>
240 double dtMin2 = w->dt * w->dt;
242 double currentDt2 = dtMin2;
244 for (
auto c : w->cells) {
246 c->getBody().receiveForce(c->getBody().getPurposeVelocity() * c->getBody().getGamma());
250 for (
auto c : w->cells) {
251 c->getBody().setComputed(
false);
253 c->getBody().setVelocity(vel);
255 if (currentDt2 < dtMin2) dtMin2 = currentDt2;
266 double delta, R, E, Frep, Fadh;
268 for (
auto c2 : c1->getConnectedCells()) {
269 if (c2 !=
nullptr && !c2->getBody().getComputed()) {
270 MecaCell::Vec rij(c2->getBody().getPosition() - c1->getBody().getPosition());
272 delta = c1->getBody().getBoundingBoxRadius() + c2->getBody().getBoundingBoxRadius() - rij.
length();
274 R = 1.0 / (1.0 / c1->getBody().getBoundingBoxRadius() + 1.0 / c2->getBody().getBoundingBoxRadius());
276 ((1.0 - c1->getBody().getPoissonNumber() * c1->getBody().getPoissonNumber()) / c1->getBody().getYoungModulus() +
277 (1.0 - c2->getBody().getPoissonNumber() * c2->getBody().getPoissonNumber()) / c2->getBody().getYoungModulus());
279 Frep = 4.0 / 3.0 * E *
sqrt(R) *
pow(delta, 3.0 / 2.0);
281 (c1->getBody().getAdhesion() + c2->getBody().getAdhesion()) / 2.0 *
284 c1->getBody().receiveForce(-direction * (Frep + Fadh));
285 c2->getBody().receiveForce(direction * (Frep + Fadh));
286 c1->getBody().addStress(
Tensor(-direction * (Frep + Fadh), rij));
287 c2->getBody().addStress(
Tensor(direction * (Frep + Fadh), -rij));
291 c1->getBody().setComputed(
true);
292 c1->getBody().divTensor(c1->getBody().getVolume());
304 template<
typename world_t>
308 for (cell_t *c : w->cells) {
310 radius = c->getBody().getBoundingBoxRadius();
312 c->getBody().setPosition(c->getBody().getPosition() + vel * dt);
326 template<
typename world_t>
328 for (cell_t *c : w->cells) {
329 c->getBody().resetForce();
342 template<
typename world_t>
351 if (time + dt > w->dt) dt = w->dt - time;
356 }
while (time < w->dt);
385 template<
typename world_t>
397 template <
typename world_t>
410 template<
typename world_t>
412 for (cell_t *c : w->cells) {
428 template<
typename world_t>
477 inline void addSymAxis(std::function<
double(
double,
MecaCell::Vec,
MecaCell::Vec)> _radiusFunction,
MecaCell::Vec _axis =
MecaCell::Vec(0., 1., 0.),
MecaCell::Vec _origin =
MecaCell::Vec(0., 0., 0.),
double _length = 100,
double _maxEffectRadius = 100,
bool _fitShape =
true,
double _velocity_attraction = 0.001) {
478 constraints.
addSymAxis(_radiusFunction, _axis, _origin, _length, _maxEffectRadius, _fitShape, _velocity_attraction);
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 Hertzian physics.
void preBehaviorUpdate(world_t *w)
Pre-behavior update hook for MecaCell.
void resetForces(world_t *w)
Resets the forces acting on the cells.
MecaCell::Vec maxConstraint
void addVelocity(MecaCell::Vec _v=MecaCell::Vec(0, 1, 0))
Adds a velocity constraint.
void moveDelaunay()
Moves the points in the triangulation to match their real positions.
void setCoherenceCoeff(double c)
Sets the coherence coefficient.
PluginHertzianPhysics()
Constructor.
void setMinConstraint(MecaCell::Vec min)
Sets the minimum constraint.
void computeDelaunay(world_t *w)
Computes the Delaunay triangulation from the list of cells.
void applyPhysics(world_t *w)
Applies the physics with a coherent time step.
double updateForces(world_t *w)
Updates the forces acting on the cells.
void addSymAxis(std::function< double(double, MecaCell::Vec, MecaCell::Vec)> _radiusFunction, MecaCell::Vec _axis=MecaCell::Vec(0., 1., 0.), MecaCell::Vec _origin=MecaCell::Vec(0., 0., 0.), double _length=100, double _maxEffectRadius=100, bool _fitShape=true, double _velocity_attraction=0.001)
Adds a symmetrical axis constraint.
PhysicsConstraints getConstraints()
Gets the physics constraints.
void preDeleteDeadCellsUpdate(world_t *w)
Pre-delete dead cells update hook for MecaCell.
void updateConnections(world_t *w)
Updates the connections between cells.
void addCells(world_t *w)
Adds new cells to the triangulation.
void beginUpdate(world_t *w)
Begin update hook for MecaCell.
void onAddCell(world_t *w)
On add cell hook for MecaCell.
bool areMovementsNegligible
void removeCells()
Removes dead cells from the triangulation.
MecaCell::Vec minConstraint
void setMaxConstraint(MecaCell::Vec max)
Sets the maximum constraint.
void setCurvedBox(double radiusBoxPlane, double curvedDistToMaxSpeed, double maxSpeed)
Sets the curved box parameters.
void customConstraint(world_t *w)
Applies custom spatial constraints to the cells.
void updateInteractionForces(cell_t *c1)
Updates the interaction forces between cells.
PhysicsConstraints constraints
void addPlane(MecaCell::Vec _n=MecaCell::Vec(0, 1, 0), MecaCell::Vec _p=MecaCell::Vec(0, 0, 0), bool _sticky=false)
Adds a plane constraint.
bool isDelaunayCoherent()
Checks the coherence of the Delaunay triangulation.
void updatePositions(world_t *w, double dt)
Updates the positions of the cells.
general purpose 3D vector/point class.
double length() const
compute the length of the vector
double sqlength() const
compute the square length of the current vector (faster than length)
Vector3D normalized() const
returns a normalized copy of the current vector
Class for managing physical constraints in a simulation.
void addPlane(MecaCell::Vec _n=MecaCell::Vec(0, 1, 0), MecaCell::Vec _p=MecaCell::Vec(0, 0, 0), bool _sticky=false)
Adds a plane constraint.
MecaCell::Vec getConstraintVelocity(cell_t *c)
Computes the constraint velocity for a cell.
void snapCellsToPlane(cell_t *c)
Snaps cells to the plane.
void addSymAxis(std::function< double(double, MecaCell::Vec, MecaCell::Vec)> _radiusFunction, MecaCell::Vec _axis=MecaCell::Vec(0., 1., 0.), MecaCell::Vec _origin=MecaCell::Vec(0., 0., 0.), double _length=100, double _maxEffectRadius=100, bool _fitShape=true, double _velocity_attraction=0.001)
Adds a symmetrical axis constraint.
void addVelocity(MecaCell::Vec _v=MecaCell::Vec(0, 1, 0))
Adds a velocity constraint.
void setCurvedBox(double radiusBoxPlane, double curvedDistToMaxSpeed, double maxSpeed)
Sets the curved box parameters.
A simple vector class template.
void reserve(size_t newCapacity)
Reserves storage for the specified number of elements.
void push_back(const T &value)
Adds an element to the end of the vector.
iterator begin()
Returns an iterator to the first element.
iterator end()
Returns an iterator to the last element.
Namespace for Hertzian physics-related classes and functions.
Vector3D Vec
alias for Vector3D
iostream cout
Standard output stream.
double sqrt(double x)
Computes the square root of a number.
iostream endl
End-of-line manipulator.
double pow(double base, double exponent)
Computes the power of a number.
Represents a 3x3 tensor for stress calculations.