CellModules
springconnection.hpp
Go to the documentation of this file.
1#ifndef MECACELL_SPRINGCONNECTION_HPP
2#define MECACELL_SPRINGCONNECTION_HPP
3#include <cmath>
4#include <utility>
5#include "spring.hpp"
8
9namespace MecaCell {
35template <typename Cell> struct SpringConnection {
37 double ADH_DAMPING_RATIO = 1.0;
38 double ANG_ADH_COEF = 10.0;
39 double ADH_CONSTANT = 1.0; // factor by which all adhesion forces is multiplied
40 double MAX_TS_INCL =
41 0.1; // max angle before we need to reproject our torsion joint rotation
42
46 std::pair<double, double>
47 midpoint; // contact disk's distance to center (viewed from each cell)
48 double sqradius = 0; // squared radius of the contact disk
49 double area = 0, adhArea = 0; // area of the contact disk
50 Vector3D direction; // normalized direction from cell 0 to cell 1
51 double dist; // distance btwn the two cells
52 std::pair<Joint, Joint> flex, tors;
53 bool adhesionEnabled = true, frictionEnabled = false, flexEnabled = false,
54 torsEnabled = false, unbreakable = false;
55 double adhCoef = 0.5;
56
59
60 std::pair<double, double> computeMidpoints(double distanceBtwnCenters) {
61 // return the current contact disk's center distance to each cells centers
62 if (dist <= Config::DOUBLE_EPSILON) return {0, 0};
63
64 auto biggestCell = cells.first->getBody().getBoundingBoxRadius() >=
65 cells.second->getBody().getBoundingBoxRadius() ?
66 cells.first :
67 cells.second;
68 auto smallestCell = biggestCell == cells.first ? cells.second : cells.first;
69
70 double biggestCellMidpoint =
71 0.5 * (distanceBtwnCenters +
72 (std::pow(biggestCell->getBody().getBoundingBoxRadius(), 2) -
73 std::pow(smallestCell->getBody().getBoundingBoxRadius(), 2)) /
74 distanceBtwnCenters);
75 double smallestCellMidpoint = distanceBtwnCenters - biggestCellMidpoint;
76 if (biggestCell == cells.first)
77 return {biggestCellMidpoint, smallestCellMidpoint};
78 else
79 return {smallestCellMidpoint, biggestCellMidpoint};
80 }
81
83 direction =
84 cells.second->getBody().getPosition() - cells.first->getBody().getPosition();
86 if (dist > 0) direction /= dist;
87 }
88
91 cells.first->getBoundingBoxRadius() + cells.second->getBoundingBoxRadius();
92 collision.k =
93 (cells.first->getBoundingBoxRadius() * cells.first->getBody().getStiffness() +
94 cells.second->getBoundingBoxRadius() * cells.second->getBody().getStiffness()) /
98 cells.first->getBody().getMass() + cells.second->getBody().getMass(),
99 collision.k);
101 sqradius = max(0.0, std::pow(cells.first->getBody().getBoundingBoxRadius(), 2) -
102 midpoint.first * midpoint.first);
103 area = M_PI * sqradius;
104 }
105
107 if (!unbreakable) {
108 adhCoef = min(
109 cells.first->getAdhesionWith(
110 cells.second,
112 cells.first->getBody().getOrientationRotation().inverted())),
113 cells.second->getAdhesionWith(
114 cells.first,
115 (-direction)
116 .rotated(cells.second->getBody().getOrientationRotation().inverted())));
117 }
121 cells.first->getBody().getMass() + cells.second->getBody().getMass(), adhesion.k);
122 }
123
124 void initJoints() {
125 auto ortho = direction.ortho();
126 // rotations for joints (cell base to connection) =
127 // cellBasis -> worldBasis + worldBasis -> connectionBasis
128 flex.first.r = cells.first->getBody().getOrientationRotation().inverted() +
130 flex.second.r = cells.second->getBody().getOrientationRotation().inverted() +
132 tors.first.r = flex.first.r;
133 tors.second.r = flex.second.r;
134
137 }
138
140 tors.first.updateDirection(cells.first->getBody().getOrientation().Y,
141 cells.first->getBody().getOrientationRotation());
142 tors.second.updateDirection(cells.second->getBody().getOrientation().Y,
143 cells.second->getBody().getOrientationRotation());
144 tors.first.k = adhesion.k * area;
145 tors.second.k = adhesion.k * area;
147 cells.first->getBody().getMomentOfInertia() +
148 cells.second->getBody().getMomentOfInertia(),
149 tors.first.k);
150 tors.second.c = tors.first.c;
151 }
152
154 flex.first.target = direction;
155 flex.first.updateDelta();
156 flex.second.target = -direction;
157 flex.second.updateDelta();
158 flex.first.updateDirection(cells.first->getBody().getOrientation().X,
159 cells.first->getBody().getOrientationRotation());
160 flex.second.updateDirection(cells.second->getBody().getOrientation().X,
161 cells.second->getBody().getOrientationRotation());
162 flex.first.k = adhesion.k * area * ANG_ADH_COEF;
163 flex.second.k = adhesion.k * area * ANG_ADH_COEF;
165 cells.first->getBody().getMomentOfInertia() +
166 cells.second->getBody().getMomentOfInertia(),
167 flex.first.k);
168 flex.second.c = flex.first.c;
169 }
170
171 void init() {
176 if (adhesionEnabled) {
180 initJoints();
181 }
182 }
183
184 template <int n> void updateJointsForces(double dt) {
185 Joint &torsNode = n == 0 ? tors.first : tors.second;
186 Joint &torsOther = n == 0 ? tors.second : tors.first;
187 Joint &flexNode = n == 0 ? flex.first : flex.second;
188 const auto &cell = cells.template get<n>();
189 const auto &other = cells.template get < n == 0 ? 1 : 0 > ();
190 const double sign = n == 0 ? 1 : -1;
191
192 if (flexNode.maxTetaAutoCorrect &&
193 flexNode.delta.teta > flexNode.maxTeta) { // if we passed flex break angle
194 double dif = flexNode.delta.teta - flexNode.maxTeta;
195 flexNode.r = flexNode.r + Rotation<Vec>(flexNode.delta.n, dif);
196 flexNode.direction =
197 flexNode.direction.rotated(Rotation<Vec>(flexNode.delta.n, dif));
198 flexNode.r = cell->getBody().getOrientationRotation().inverted() +
200 flexNode.direction.ortho()));
201 }
202 flexNode.delta.n.normalize();
203 double torque =
204 flexNode.k * flexNode.delta.teta +
205 flexNode.c * ((flexNode.delta.teta - flexNode.prevDelta.teta) / dt); // -kx - cv
206 Vec vFlex = flexNode.delta.n * torque; // torque
207 Vec ortho = direction.ortho(flexNode.delta.n).normalized(); // force direction
208 Vec force = sign * ortho * torque / dist;
209
210 cell->getBody().receiveForce(-force);
211 other->getBody().receiveForce(force);
212
213 cell->getBody().receiveTorque(vFlex);
214 flexNode.prevDelta = flexNode.delta;
215 if (torsEnabled) {
216 // updating torsion joint (needs to stay perp to direction)
217 double scalar = torsNode.direction.dot(direction);
218 // if the angle between our torsion spring and direction is too far from 90°,
219 // we reproject & recompute it
220 if (abs(scalar) > MAX_TS_INCL) {
221 torsNode.r = cell->getBody().getOrientationRotation().inverted() +
222 Vec::getRotation(Basis<Vec>(Vec(1, 0, 0), Vec(0, 1, 0)),
223 Basis<Vec>(direction, torsNode.direction));
224 } else
225 torsNode.direction = torsNode.direction.normalized() - scalar * direction;
226 // updating targets
227 torsNode.target =
228 torsOther.direction; // we want torsion springs to stay aligned with each other
229 torsNode.updateDelta();
230 // torsion torque
231 double torsionTorque = torsNode.k * torsNode.delta.teta; // - torsNode.c *
232 // cell->getAngularVelocity().dot(torsNode.delta.teta.n)
233 Vec vTorsion = torsionTorque * torsNode.delta.n;
234 cell->getBody().receiveTorque(vTorsion);
235 }
236 }
237
238 void update(double dt) {
240 // updating collision and adhesion springs
243 collision.applyForce(cells.first->getBody(), cells.second->getBody(), direction, dt);
244 if (adhesionEnabled) {
247 adhesion.applyForce(cells.first->getBody(), cells.second->getBody(), direction, dt);
250 if (flexEnabled || torsEnabled) {
251 updateJointsForces<0>(dt);
252 updateJointsForces<1>(dt);
253 }
254 }
255 }
256};
257} // namespace MecaCell
258#endif
general purpose 3D vector/point class.
Definition: vector3D.h:20
double length() const
compute the length of the vector
Definition: vector3D.h:257
static Rotation< Vector3D > getRotation(const Vector3D &v0, const Vector3D &v1)
computes the rotation from one vector to another
Definition: vector3D.h:322
Vector3D ortho() const
deterministic generation of an orthogonal vector
Definition: vector3D.h:519
Vector3D rotated(double angle, const Vector3D &vec) const
gives a rotated copy of the current vector
Definition: vector3D.h:277
double dot(const Vector3D &v) const
dot product calculation
Definition: vector3D.h:54
Vector3D normalized() const
returns a normalized copy of the current vector
Definition: vector3D.h:452
this file contains various miscellanious utility functions & helpers *
Vector3D Vec
alias for Vector3D
Definition: utils.hpp:22
double dampingFromRatio(const double r, const double m, const double k)
Definition: utils.hpp:133
int abs(int x)
Computes the absolute value of an integer.
Definition: std.hpp:83
double pow(double base, double exponent)
Computes the power of a number.
Definition: std.hpp:43
static constexpr double DOUBLE_EPSILON
max distance for two doubles to be considered equals (only used for some geometric operations)
Definition: config.hpp:22
bool maxTetaAutoCorrect
Definition: spring.hpp:54
double maxTeta
Definition: spring.hpp:48
Rotation< Vec > r
Definition: spring.hpp:49
void updateDelta()
Definition: spring.hpp:65
Rotation< Vec > delta
Definition: spring.hpp:50
Rotation< Vec > prevDelta
Definition: spring.hpp:51
A Spring Connection is a connection between two cells that aims to models both attractive (for adhesi...
SpringConnection(ordered_pair< Cell * > c)
ordered_pair< Cell * > cells
std::pair< Joint, Joint > flex
std::pair< Joint, Joint > tors
std::pair< double, double > computeMidpoints(double distanceBtwnCenters)
std::pair< double, double > midpoint
double restLength
Definition: spring.hpp:13
void updateLength(double l)
Definition: spring.hpp:22
void applyForce(A &a, B &b, const Vector3D &direction, double dt)
Definition: spring.hpp:33
double prevLength
Definition: spring.hpp:15
double length
Definition: spring.hpp:14