CellModules
contactsurface.hpp
Go to the documentation of this file.
1#ifndef CONTACTSURFACE_HPP
2#define CONTACTSURFACE_HPP
3#include <cmath>
4#include <utility>
7
8namespace MecaCell {
9template <typename Cell> struct ContactSurface {
11
12 /***********************************************************
13 * SETTABLE PARAMETERS
14 **********************************************************/
15 bool pressureEnabled = true;
16 bool adhesionEnabled = true;
17 bool frictionEnabled = false;
18 bool unbreakable = false; // is this adhesion unbreakable ?
19
21 double adhCoef = 0.5; // adhesion Coef [0;1]
22 double ADH_DAMPING_RATIO= 0.1; // damping [0;1]
23 double bondMaxL = 5.0; // max length a surface bond can reach before breaking
24 double bondReach = 1.0; // when are new connection created [0;bondMaxL[
25 double fixedDamping = 0.0;
26 double baseBondStrength = 0.05;
27 double MIN_ADH_DIST = 8.0;
28
29 /*********************************************************
30 * INTERNALS
31 ********************************************************/
32 Vec direction; // direction of the actual contact surface (from cell 0 to cell 1)
33 std::pair<double, double> midpoint; // distance to center (viewed from each cell)
34 double sqradius = 0; // squared radius of the contact disk
35 double area = 0, adhArea = 0; // area of the contact disk
36 double centersDist = 0, prevCentersDist = 0; // distance of the two cells centers
37 double prevLinAdhElongation = 0, linAdhElongation = 0; // the elongation of the
38 // connections caused by the
39 // cells separation
40 double prevFlexAdhElongation = 0, flexAdhElongation = 0; // the elongation of the
41 // connections caused by the
42 // cells relative flexure
44 // TODO: implement friction...
45 bool atRest = false; // are the cells at rest, relatively to each other ?
46 static constexpr double REST_EPSILON =
47 1e-10; // minimal speed to consider the connected Cells not to be at rest
48
51 Basis<Vec> b; // X is the direction of the surface, Y is the up vector
52 // b is expressed in the cell's basis, thus if we want to compute b in world basis :
53 // Bw = b.rotated(cell->getOrientationRotation());
54 double d; // distance to center of cell
55 };
56
57 std::pair<TargetSurface, TargetSurface> targets;
58
59 /*********************************************************
60 * CONSTRUCTORS
61 ********************************************************/
65 if (adhesionEnabled) {
66 // we need to init the targets
67 Vec ortho = direction.ortho();
68 targets.first.b = Basis<Vec>(
69 direction.rotated(cells.first->getBody().getOrientationRotation().inverted()),
70 ortho.rotated(cells.first->getBody().getOrientationRotation().inverted()));
71 targets.first.d = midpoint.first / cells.first->getBody().getDynamicRadius();
72 targets.second.b = Basis<Vec>(
73 (-direction)
74 .rotated(cells.second->getBody().getOrientationRotation().inverted()),
75 ortho.rotated(cells.second->getBody().getOrientationRotation().inverted()));
76 targets.second.d = midpoint.second / cells.second->getBody().getDynamicRadius();
77 }
78 }
79
80 /*********************************************************
81 * MAIN UPDATE
82 ********************************************************/
83 void update(double dt) {
84 // first we update all the internals
86 // then we apply all the forces
89 }
90
91 /*********************************************************
92 * INTERNALS UPDATES
93 ********************************************************/
95 direction = cells.second->getPosition() - cells.first->getPosition();
100 sqradius = max(0.0, std::pow(cells.first->getBody().getDynamicRadius(), 2) -
101 midpoint.first * midpoint.first);
102 area = M_PI * sqradius;
103 adhCoef = min(
104 cells.first->getAdhesionWith(
105 cells.second,
107 cells.first->getBody().getOrientationRotation().inverted())),
108 cells.second->getAdhesionWith(
109 cells.first,
110 (-direction)
111 .rotated(cells.second->getBody().getOrientationRotation().inverted())));
112 }
113
114 std::pair<double, double> computeMidpoints(double distanceBtwnCenters) {
115 // return the current contact disk's center distance to each cells centers
116 if (distanceBtwnCenters <= Config::DOUBLE_EPSILON) return {0, 0};
117
118 auto biggestCell = cells.first->getBody().getDynamicRadius() >=
119 cells.second->getBody().getDynamicRadius() ?
120 cells.first :
121 cells.second;
122 auto smallestCell = biggestCell == cells.first ? cells.second : cells.first;
123
124 double biggestCellMidpoint =
125 0.5 *
126 (distanceBtwnCenters + (std::pow(biggestCell->getBody().getDynamicRadius(), 2) -
127 std::pow(smallestCell->getBody().getDynamicRadius(), 2)) /
128 distanceBtwnCenters);
129 double smallestCellMidpoint = distanceBtwnCenters - biggestCellMidpoint;
130 if (biggestCell == cells.first)
131 return {biggestCellMidpoint, smallestCellMidpoint};
132 else
133 return {smallestCellMidpoint, biggestCellMidpoint};
134 }
135
136 /*********************************************************
137 * FORCES COMPUTATIONS
138 ********************************************************/
139 // All forces applying method assume the internal values have
140 // correctly been updated before
141
142 // from internal pressure
143 void applyPressureForces(double) {
144 // force from pressure is direction to the actual contact surface
145 // and proportional to its surface
146 // double adhSpeed = (centersDist - prevCentersDist) / dt;
147 auto F = 0.5 *
148 (area * (max(0.0, cells.first->getBody().getPressure()) +
149 max(0.0, cells.second->getBody().getPressure()))) *
150 direction;
151 cells.first->getBody().receiveForce(-F);
152 cells.second->getBody().receiveForce(F);
153 }
154
155 void applyAdhesiveForces(double dt) {
156 // two main spring like forces :
157 // torsion + linear = targets points trying to meet.
158 // flexure = midpoint trying to align with the targets points.
159 std::pair<double, double> computedTargetsDistances = {
160 targets.first.d * cells.first->getBody().getDynamicRadius(),
161 targets.second.d * cells.second->getBody().getDynamicRadius()};
162 // first we express our targets basis into world basis
163 std::pair<Basis<Vec>, Basis<Vec>> targetsBw = {
164 targets.first.b.rotated(cells.first->getBody().getOrientationRotation()),
165 targets.second.b.rotated(cells.second->getBody().getOrientationRotation())};
166
167 // projections of the target directions onto the current actual collision surface
168 Vec midpointPos =
169 cells.first->getPosition() +
170 direction * midpoint.first; // we need the actual midpoint position;
171
172 // std::pair<double, double> projDist = {
173 // Vec::rayCast(midpointPos, direction, cells.first->getPosition(),
174 // targetsBw.first.X),
175 // Vec::rayCast(midpointPos, direction, cells.second->getPosition(),
176 // targetsBw.second.X)};
177 // if (!fixedAdhesion && projDist.first > MIN_ADH_DIST &&
178 // projDist.first - bondReach < computedTargetsDistances.first) {
180 // computedTargetsDistances.first = projDist.first - bondReach;
181 // targets.first.d =
182 // computedTargetsDistances.first / cells.first->getBody().getDynamicRadius();
183 //}
184 // if (!fixedAdhesion && projDist.second > MIN_ADH_DIST &&
185 // projDist.second - bondReach < computedTargetsDistances.second) {
186 // computedTargetsDistances.second = projDist.second - bondReach;
187 // targets.second.d =
188 // computedTargetsDistances.second / cells.second->getBody().getDynamicRadius();
189 //}
190 if (computedTargetsDistances.first < MIN_ADH_DIST) {
191 computedTargetsDistances.first = MIN_ADH_DIST;
192 targets.first.d =
193 computedTargetsDistances.first / cells.first->getBody().getDynamicRadius();
194 }
195 if (computedTargetsDistances.second < MIN_ADH_DIST) {
196 computedTargetsDistances.second = MIN_ADH_DIST;
197 targets.second.d =
198 computedTargetsDistances.second / cells.second->getBody().getDynamicRadius();
199 }
200 // we can now compute the target centers;
201 std::pair<Vec, Vec> o = {
202 cells.first->getPosition() + computedTargetsDistances.first * targetsBw.first.X,
203 cells.second->getPosition() +
204 computedTargetsDistances.second * targetsBw.second.X};
205
206 // now we apply the forces exerted by all the connections.
207 // we apply them at the centers of the two targets
208
209 // compute the connected area. Only needed when the sum of the targets.d changes
210 adhArea =
211 max(0.0,
212 std::pow(cells.first->getBody().getDynamicRadius(), 2) -
213 std::pow(std::get<0>(computeMidpoints(computedTargetsDistances.first +
214 computedTargetsDistances.second)),
215 2)) *
216 M_PI;
217 // we can now compute the forces applied at o.first & o.second
218 Vec o0o1 = o.second - o.first;
220 linAdhElongation = o0o1.length();
221 // targets midpoint, where the actual midpoint is going to try to align
222 Vec targetMidpoint = o.first + o0o1 / 2;
223 Vec m0m1 = targetMidpoint - midpointPos;
225 flexAdhElongation = m0m1.length();
226
227 // on axis forces
229 o0o1 /= linAdhElongation;
231 // some bonds are going to break
232 double halfD = 0.5 * (linAdhElongation - bondMaxL);
233 o.first += halfD * o0o1;
234 o.second -= halfD * o0o1;
235 auto newX = (o.first - cells.first->getPosition());
236 auto newD = newX.length();
237 if (newD > 0)
238 newX /= newD;
239 else
240 newX = Vec(1, 0, 0);
241 targets.first.b.X =
242 newX.rotated(cells.first->getBody().getOrientationRotation().inverted());
243 targets.first.d = newD / cells.first->getBody().getDynamicRadius();
244 newX = (o.second - cells.second->getPosition());
245 newD = newX.length();
246 if (newD > 0)
247 newX /= newD;
248 else
249 newX = Vec(1, 0, 0);
250 targets.second.b.X =
251 newX.rotated(cells.second->getBody().getOrientationRotation().inverted());
252 targets.second.d = newD / cells.second->getBody().getDynamicRadius();
254 }
255 double springSpeed = (linAdhElongation - prevLinAdhElongation) / dt;
256 double k = adhArea * adhCoef * baseBondStrength;
257 double ratioDamping = dampingFromRatio(
258 ADH_DAMPING_RATIO, cells.first->getBody().getMass() + cells.second->getBody().getMass(),
259 k);
260
261 Vec F = 0.5 * (k * linAdhElongation + (fixedDamping + ratioDamping) * springSpeed) *
262 o0o1;
263 // cells.first receive F at o0 and in the direction o0o1
264 cells.first->getBody().receiveForce(F);
265 cells.first->getBody().receiveTorque(
266 (targetsBw.first.X * computedTargetsDistances.first).cross(F));
267 // cells.second receive F at o1 and in the direction -o0o1
268 cells.second->getBody().receiveForce(-F);
269 cells.second->getBody().receiveTorque(
270 (targetsBw.second.X * computedTargetsDistances.second).cross(-F));
271 }
272 // midpoints alignment forces
273 // if (flexAdhElongation > DIST_EPSILON) {
274 // double springSpeed = (flexAdhElongation - prevFlexAdhElongation) / dt;
275 // double k = adhArea * adhCoef * baseBondStrength;
276 // double ratioDamping =
277 // dampingFromRatio(ADH_DAMPING_RATIO, cells.first->getMass() + cells.second->getMass(), k);
278 // Vec F = 0.5 *
279 //(k * flexAdhElongation + (fixedDamping + ratioDamping) * springSpeed) *
280 // m0m1;
282 // cells.first->getBody().receiveTorque(
283 //(targetsBw.first.X * computedTargetsDistances.first).cross(F));
286 // cells.second->getBody().receiveTorque(
287 //(targetsBw.second.X * computedTargetsDistances.second).cross(F));
288 //}
289 }
290};
291} // namespace MecaCell
292#endif
general purpose 3D vector/point class.
Definition: vector3D.h:20
double length() const
compute the length of the vector
Definition: vector3D.h:257
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
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
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
std::pair< double, double > computeMidpoints(double distanceBtwnCenters)
ordered_pair< Cell * > cells
void applyAdhesiveForces(double dt)
ContactSurface(ordered_pair< Cell * > c)
std::pair< double, double > midpoint
std::pair< TargetSurface, TargetSurface > targets
static constexpr double REST_EPSILON