37 #include <ompl/control/SpaceInformation.h>
38 #include "KoulesStateSpace.h"
39 #include "KoulesControlSpace.h"
40 #include "KoulesSimulator.h"
47 inline double normalizeAngle(
double theta)
49 if (theta < -boost::math::constants::pi<double>())
50 return theta + 2. * boost::math::constants::pi<double>();
51 if (theta > boost::math::constants::pi<double>())
52 return theta - 2. * boost::math::constants::pi<double>();
56 inline void normalize2(
double* v)
58 double nrm = std::sqrt(v[0] * v[0] + v[1] * v[1]);
59 if (nrm > std::numeric_limits<double>::epsilon())
70 inline double dot2(
const double* v,
const double* w)
72 return v[0] * w[0] + v[1] * w[1];
74 inline void vadd2(
double* v,
double s,
const double* w)
79 inline unsigned int ind(
unsigned int i)
81 return i != 0u ? 4 * i + 1 : 0;
83 inline void ode(
const double* y,
double* dydx)
87 dydx[2] = (.5 * sideLength - y[0]) * lambda_c - y[2] * h;
88 dydx[3] = (.5 * sideLength - y[1]) * lambda_c - y[3] * h;
90 inline void rungeKutta4(
double* y,
double h,
double* yout)
92 double hh = h * .5, h6 = h / 6.;
93 static double yt[4], dydx[4], dym[4], dyt[4];
95 for (
unsigned int i = 0; i < 4; ++i)
96 yt[i] = y[i] + hh * dydx[i];
98 for (
unsigned int i = 0; i < 4; ++i)
99 yt[i] = y[i] + hh * dyt[i];
101 for (
unsigned int i = 0; i < 4; ++i)
103 yt[i] = y[i] + h * dym[i];
107 for (
unsigned int i = 0; i < 4; ++i)
108 yout[i] = y[i] + h6 * (dydx[i] + dyt[i] + 2. * dym[i]);
111 const float eps = std::numeric_limits<float>::epsilon();
116 numDimensions_(si->getStateSpace()->getDimension()),
117 numKoules_((numDimensions_ - 5) / 4),
118 qcur_(numDimensions_),
119 qnext_(numDimensions_),
120 dead_(numKoules_ + 1)
124 void KoulesSimulator::updateShip(
const oc::Control* control,
double t)
127 double v[2] = { cval[0] - qcur_[2], cval[1] - qcur_[3] };
128 double deltaTheta = normalizeAngle(atan2(v[1], v[0]) - qcur_[4]);
129 double accel = 0., omega = 0.;
131 if (std::abs(deltaTheta) < shipEps)
133 if (v[0] * v[0] + v[1] * v[1] > shipDelta * shipDelta)
134 accel = shipAcceleration;
137 omega = deltaTheta > 0. ? shipRotVel : -shipRotVel;
141 qnext_[0] = qcur_[0] + qcur_[2] * t;
142 qnext_[1] = qcur_[1] + qcur_[3] * t;
143 qnext_[2] = qcur_[2];
144 qnext_[3] = qcur_[3];
145 qcur_[4] = normalizeAngle(qcur_[4] + omega * t);
149 double ax = accel * cos(qcur_[4]);
150 double ay = accel * sin(qcur_[4]);
151 double t2 = .5 * t * t;
152 qnext_[0] = qcur_[0] + qcur_[2] * t + ax * t2;
153 qnext_[1] = qcur_[1] + qcur_[3] * t + ay * t2;
154 qnext_[2] = qcur_[2] + ax * t;
155 qnext_[3] = qcur_[3] + ay * t;
159 void KoulesSimulator::initCollisionEvents()
161 double r[2], d, bad, ri, rij;
163 collisionEvents_ = CollisionEventQueue();
164 for (
unsigned int i = 0; i < numKoules_; ++i)
168 ri = si_->
getStateSpace()->as<KoulesStateSpace>()->getRadius(i);
169 for (
unsigned int j = i + 1; j <= numKoules_; ++j)
173 rij = ri + si_->
getStateSpace()->as<KoulesStateSpace>()->getRadius(j);
174 r[0] = qcur_[jj ] - qcur_[ii ];
175 r[1] = qcur_[jj + 1] - qcur_[ii + 1];
176 d = r[0] * r[0] + r[1] * r[1];
182 r[0] *= bad * (1. + eps) * .5;
184 r[1] *= bad * (1. + eps) * .5;
186 qcur_[ii + 1] -= r[1];
188 qcur_[jj + 1] += r[1];
192 for (
unsigned int i = 0; i <= numKoules_; ++i)
193 for (
unsigned int j = i + 1; j <= numKoules_ + 2; ++j)
194 computeCollisionEvent(i, j);
197 double KoulesSimulator::wallCollideEvent(
unsigned int i,
int dim)
199 double r = si_->
getStateSpace()->as<KoulesStateSpace>()->getRadius(i);
200 unsigned int ii = ind(i);
201 if (qcur_[ii + 2 + dim] > 0.)
202 return std::max(0., (sideLength - r - qcur_[ii + dim]) / qcur_[ii + 2 + dim]);
203 if (qcur_[ii + 2 + dim] < 0.)
204 return std::max(0., (r - qcur_[ii + dim]) / qcur_[ii + 2 + dim]);
209 void KoulesSimulator::computeCollisionEvent(
unsigned int i,
unsigned int j)
211 if (dead_[i] || (j <= numKoules_ && dead_[j]))
214 double ri = si_->
getStateSpace()->as<KoulesStateSpace>()->getRadius(i);
217 if (j == numKoules_ + 1)
218 t = wallCollideEvent(i, 0);
219 else if (j == numKoules_ + 2)
220 t = wallCollideEvent(i, 1);
223 unsigned int ii = ind(i), jj = ind(j);
224 double u[2] = { qcur_[ii + 2] - qcur_[jj + 2], qcur_[ii + 3] - qcur_[jj + 3] };
225 double v[2] = { qcur_[ii ] - qcur_[jj ], qcur_[ii + 1] - qcur_[jj + 1] };
226 double a = u[0] * u[0] + u[1] * u[1];
231 double r = ri + si_->
getStateSpace()->as<KoulesStateSpace>()->getRadius(j);
232 double b = 2 * u[0] * v[0] + 2 * u[1] * v[1];
233 double c = v[0] * v[0] + v[1] * v[1] - r * r;
234 double disc = b * b - 4. * a * c;
235 if (std::abs(disc) < std::numeric_limits<float>::epsilon())
241 disc = std::sqrt(disc);
242 t = (-b - disc) / (2. * a);
244 t = (-b + disc) / (2. * a);
249 if (t >= time_ && t <= endTime_)
250 collisionEvents_.emplace(t, i, j);
253 void KoulesSimulator::elasticCollision(
unsigned int i,
unsigned int j)
255 double *a = &qcur_[ind(i)], *b = &qcur_[ind(j)];
256 double d[2] = { b[0] - a[0], b[1] - a[1] };
258 double va = dot2(a + 2, d), vb = dot2(b + 2, d);
261 double ma = si_->
getStateSpace()->as<KoulesStateSpace>()->getMass(i);
262 double mb = si_->
getStateSpace()->as<KoulesStateSpace>()->getMass(j);
263 double vap = (va * (ma - mb) + 2. * mb * vb) / (ma + mb);
264 double vbp = (vb * (mb - ma) + 2. * ma * va) / (ma + mb);
265 double amag = vap - va, bmag = vbp - vb;
266 if (std::abs(amag) < eps)
267 amag = amag < 0. ? -eps : eps;
268 if (std::abs(bmag) < eps)
269 bmag = bmag < 0. ? -eps : eps;
271 double px = ma * a[2] + mb * b[2], py = ma * a[3] + mb * b[3];
272 double k = ma * (a[2] * a[2] + a[3] * a[3]) + mb * (b[2] * b[2] + b[3] * b[3]);
274 vadd2(a + 2, amag, d);
275 vadd2(b + 2, bmag, d);
279 assert(std::abs(ma * a[2] + mb * b[2] - px) < 1e-6);
280 assert(std::abs(ma * a[3] + mb * b[3] - py) < 1e-6);
282 assert(std::abs(ma * (a[2] * a[2] + a[3] * a[3]) + mb * (b[2] * b[2] + b[3] * b[3]) - k) < 1e-6);
286 void KoulesSimulator::advance(
double t)
288 double dt = t - time_;
289 qcur_[0] += qcur_[2] * dt;
290 qcur_[1] += qcur_[3] * dt;
291 for (
unsigned int i = 5; i < numDimensions_; i += 4)
293 qcur_[i ] += qcur_[i + 2] * dt;
294 qcur_[i + 1] += qcur_[i + 3] * dt;
299 void KoulesSimulator::markAsDead(
unsigned int i)
301 unsigned int ii = ind(i);
302 qcur_[ii] = -2. * kouleRadius;
303 qcur_[ii + 1] = qcur_[ii + 2] = qcur_[ii + 3] = 0.;
311 memcpy(&qcur_[0], start->
as<KoulesStateSpace::StateType>()->values, numDimensions_ *
sizeof(
double));
314 std::fill(dead_.begin(), dead_.end(),
false);
315 updateShip(control, t);
316 for (
unsigned int i = 0; i <= numKoules_; ++i)
319 dead_[i] = qcur_[ii] == -2. * kouleRadius;
323 rungeKutta4(&qcur_[ii], t, &qnext_[ii]);
324 qcur_[ii + 2] = (qnext_[ii ] - qcur_[ii ]) / t;
325 qcur_[ii + 3] = (qnext_[ii + 1] - qcur_[ii + 1]) / t;
328 initCollisionEvents();
329 while (!collisionEvents_.empty())
331 CollisionEvent
event = collisionEvents_.top();
332 double ct = std::get<0>(event);
333 unsigned int i = std::get<1>(event), j = std::get<2>(event);
335 collisionEvents_.pop();
338 elasticCollision(i, j);
344 memcpy(result->
as<KoulesStateSpace::StateType>()->values, &qcur_[0], numDimensions_ *
sizeof(
double));
349 for (
unsigned int k = 0; k <= numKoules_ + 2; ++k)
352 computeCollisionEvent(k, i);
353 else if (k > i && k != j)
354 computeCollisionEvent(i, k);
356 computeCollisionEvent(k, j);
358 computeCollisionEvent(j, k);
362 memcpy(result->
as<KoulesStateSpace::StateType>()->values, &qcur_[0], numDimensions_ *
sizeof(
double));