Warning, file /education/step/stepcore/world.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "world.h" 0008 #include "solver.h" 0009 #include "collisionsolver.h" 0010 #include "constraintsolver.h" 0011 0012 #include <algorithm> 0013 #include <cmath> 0014 #include <QtGlobal> 0015 0016 namespace StepCore 0017 { 0018 0019 0020 STEPCORE_META_OBJECT(Tool, QT_TRANSLATE_NOOP("ObjectClass", "Tool"), QT_TRANSLATE_NOOP("ObjectDescription", "Tool"), MetaObject::ABSTRACT,,) 0021 0022 STEPCORE_META_OBJECT(World, QT_TRANSLATE_NOOP("ObjectClass", "World"), QT_TRANSLATE_NOOP("ObjectDescription", "World"), 0, STEPCORE_SUPER_CLASS(ItemGroup), 0023 STEPCORE_PROPERTY_RW_D(double, time, QT_TRANSLATE_NOOP("PropertyName", "time"), QT_TRANSLATE_NOOP("Units", "s"), QT_TRANSLATE_NOOP("PropertyDescription", "Current time"), time, setTime) 0024 STEPCORE_PROPERTY_RW (double, timeScale, QT_TRANSLATE_NOOP("PropertyName", "timeScale"), STEPCORE_UNITS_1, QT_TRANSLATE_NOOP("PropertyDescription", "Simulation speed scale"), timeScale, setTimeScale) 0025 STEPCORE_PROPERTY_RW (bool, errorsCalculation, QT_TRANSLATE_NOOP("PropertyName", "errorsCalculation"), STEPCORE_UNITS_NULL, 0026 QT_TRANSLATE_NOOP("PropertyDescription", "Enable global error calculation"), errorsCalculation, setErrorsCalculation)) 0027 0028 World::World() 0029 : _time(0), _timeScale(1), _errorsCalculation(false), 0030 _solver(nullptr), _collisionSolver(nullptr), _constraintSolver(nullptr), 0031 _variablesCount(0) 0032 { 0033 setColor(0xffffffff); 0034 setWorld(this); 0035 clear(); 0036 } 0037 0038 World::World(const World& world) 0039 : ItemGroup(), _time(0), _timeScale(1), _errorsCalculation(false), 0040 _solver(nullptr), _collisionSolver(nullptr), _constraintSolver(nullptr), 0041 _variablesCount(0) 0042 { 0043 *this = world; 0044 } 0045 0046 World::~World() 0047 { 0048 clear(); 0049 } 0050 0051 void World::clear() 0052 { 0053 // Avoid erasing each element individually in the cache 0054 if(_collisionSolver) _collisionSolver->resetCaches(); 0055 0056 // clear _items 0057 ItemGroup::clear(); 0058 0059 STEPCORE_ASSERT_NOABORT(_bodies.empty()); 0060 STEPCORE_ASSERT_NOABORT(_forces.empty()); 0061 STEPCORE_ASSERT_NOABORT(_joints.empty()); 0062 //_bodies.clear(); 0063 //_forces.clear(); 0064 0065 delete _solver; _solver = nullptr; 0066 delete _collisionSolver; _collisionSolver = nullptr; 0067 delete _constraintSolver; _constraintSolver = nullptr; 0068 0069 _variablesCount = 0; 0070 _variables.resize(0); 0071 _variances.resize(0); 0072 _tempArray.resize(0); 0073 0074 _constraintsInfo.setDimension(0, 0); 0075 0076 setColor(0xffffffff); 0077 deleteObjectErrors(); 0078 0079 _time = 0; 0080 _timeScale = 1; 0081 _errorsCalculation = false; 0082 0083 _stopOnCollision = false; 0084 _stopOnIntersection = false; 0085 _evolveAbort = false; 0086 0087 #ifdef STEPCORE_WITH_QT 0088 setName(QString()); 0089 #endif 0090 } 0091 0092 World& World::operator=(const World& world) 0093 { 0094 if(this == &world) return *this; 0095 0096 clear(); 0097 ItemGroup::operator=(world); 0098 0099 if(world._solver) { 0100 setSolver(static_cast<Solver*>( 0101 world._solver->metaObject()->cloneObject(*(world._solver)))); 0102 } else setSolver(nullptr); 0103 0104 if(world._collisionSolver) { 0105 setCollisionSolver(static_cast<CollisionSolver*>( 0106 world._collisionSolver->metaObject()->cloneObject(*(world._collisionSolver)))); 0107 } else setCollisionSolver(nullptr); 0108 0109 if(world._constraintSolver) setConstraintSolver(static_cast<ConstraintSolver*>( 0110 world._constraintSolver->metaObject()->cloneObject(*(world._constraintSolver)))); 0111 else setConstraintSolver(nullptr); 0112 0113 _time = world._time; 0114 _timeScale = world._timeScale; 0115 _errorsCalculation = world._errorsCalculation; 0116 0117 _stopOnCollision = world._stopOnCollision; 0118 _stopOnIntersection = world._stopOnIntersection; 0119 _evolveAbort = world._evolveAbort; 0120 0121 // Fix links 0122 QHash<const Object*, Object*> copyMap; 0123 copyMap.insert(NULL, NULL); 0124 copyMap.insert(&world, this); 0125 if(_solver) copyMap.insert(world._solver, _solver); 0126 if(_collisionSolver) copyMap.insert(world._collisionSolver, _collisionSolver); 0127 if(_constraintSolver) copyMap.insert(world._constraintSolver, _constraintSolver); 0128 fillCopyMap(©Map, &world, this); 0129 0130 applyCopyMap(©Map, this); 0131 if(_solver) applyCopyMap(©Map, _solver); 0132 if(_collisionSolver) applyCopyMap(©Map, _collisionSolver); 0133 if(_constraintSolver) applyCopyMap(©Map, _constraintSolver); 0134 0135 const ItemList::const_iterator end = items().end(); 0136 for(ItemList::const_iterator it = items().begin(); it != end; ++it) { 0137 worldItemCopied(©Map, *it); 0138 } 0139 0140 setWorld(this); 0141 0142 checkVariablesCount(); 0143 0144 return *this; 0145 } 0146 0147 void World::fillCopyMap(QHash<const Object*, Object*>* map, 0148 const ItemGroup* g1, ItemGroup* g2) 0149 { 0150 const ItemList::const_iterator end = g1->items().end(); 0151 for(ItemList::const_iterator it1 = g1->items().begin(), 0152 it2 = g2->items().begin(); 0153 it1 != end; ++it1, ++it2) { 0154 map->insert(*it1, *it2); 0155 if((*it1)->metaObject()->inherits<StepCore::ItemGroup>()) 0156 fillCopyMap(map, static_cast<ItemGroup*>(*it1), static_cast<ItemGroup*>(*it2)); 0157 } 0158 } 0159 0160 void World::applyCopyMap(QHash<const Object*, Object*>* map, Object* obj) 0161 { 0162 const StepCore::MetaObject* mobj = obj->metaObject(); 0163 for(int i=0; i<mobj->propertyCount(); ++i) { 0164 const StepCore::MetaProperty* pr = mobj->property(i); 0165 if(pr->userTypeId() == qMetaTypeId<Object*>()) { 0166 QVariant v = pr->readVariant(obj); 0167 v = QVariant::fromValue(map->value(v.value<Object*>(), NULL)); 0168 pr->writeVariant(obj, v); 0169 } 0170 } 0171 } 0172 0173 void World::worldItemCopied(QHash<const Object*, Object*>* map, Item* item) 0174 { 0175 applyCopyMap(map, item); 0176 0177 if(item->metaObject()->inherits<Force>()) 0178 _forces.push_back(dynamic_cast<Force*>(item)); 0179 if(item->metaObject()->inherits<Joint>()) 0180 _joints.push_back(dynamic_cast<Joint*>(item)); 0181 if(item->metaObject()->inherits<Body>()) 0182 _bodies.push_back(dynamic_cast<Body*>(item)); 0183 0184 if(item->metaObject()->inherits<ItemGroup>()) { 0185 ItemGroup* group = static_cast<ItemGroup*>(item); 0186 ItemList::const_iterator end = group->items().end(); 0187 for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) { 0188 worldItemCopied(map, *it); 0189 } 0190 } 0191 } 0192 0193 void World::worldItemAdded(Item* item) 0194 { 0195 if(item->metaObject()->inherits<Force>()) 0196 _forces.push_back(dynamic_cast<Force*>(item)); 0197 0198 if(item->metaObject()->inherits<Joint>()) 0199 _joints.push_back(dynamic_cast<Joint*>(item)); 0200 0201 if(item->metaObject()->inherits<Body>()) { 0202 Body* body = dynamic_cast<Body*>(item); 0203 _bodies.push_back(body); 0204 if(_collisionSolver) _collisionSolver->bodyAdded(_bodies, body); 0205 } 0206 0207 if(item->metaObject()->inherits<ItemGroup>()) { 0208 ItemGroup* group = static_cast<ItemGroup*>(item); 0209 ItemList::const_iterator end = group->items().end(); 0210 for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) { 0211 worldItemAdded(*it); 0212 } 0213 } 0214 0215 checkVariablesCount(); 0216 } 0217 0218 void World::worldItemRemoved(Item* item) 0219 { 0220 if(item->metaObject()->inherits<ItemGroup>()) { 0221 ItemGroup* group = static_cast<ItemGroup*>(item); 0222 ItemList::const_iterator end = group->items().end(); 0223 for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) { 0224 worldItemRemoved(*it); 0225 } 0226 } 0227 0228 const ItemList::const_iterator end = items().end(); 0229 for(ItemList::const_iterator it = items().begin(); it != end; ++it) { 0230 (*it)->worldItemRemoved(item); 0231 } 0232 0233 if(item->metaObject()->inherits<Body>()) { 0234 Body* body = dynamic_cast<Body*>(item); 0235 if(_collisionSolver) _collisionSolver->bodyRemoved(_bodies, body); 0236 BodyList::iterator b = std::find(_bodies.begin(), _bodies.end(), body); 0237 STEPCORE_ASSERT_NOABORT(b != _bodies.end()); 0238 _bodies.erase(b); 0239 } 0240 0241 if(item->metaObject()->inherits<Joint>()) { 0242 JointList::iterator j = std::find(_joints.begin(), _joints.end(), 0243 dynamic_cast<Joint*>(item)); 0244 STEPCORE_ASSERT_NOABORT(j != _joints.end()); 0245 _joints.erase(j); 0246 } 0247 0248 if(item->metaObject()->inherits<Force>()) { 0249 ForceList::iterator f = std::find(_forces.begin(), _forces.end(), 0250 dynamic_cast<Force*>(item)); 0251 STEPCORE_ASSERT_NOABORT(f != _forces.end()); 0252 _forces.erase(f); 0253 } 0254 0255 // XXX: on ItemGroup::clear this will be called on each object ! 0256 checkVariablesCount(); 0257 } 0258 0259 /* 0260 void World::addItem(Item* item) 0261 { 0262 _items.push_back(item); 0263 item->setWorld(this); 0264 Force* force = dynamic_cast<Force*>(item); 0265 if(force) _forces.push_back(force); 0266 Body* body = dynamic_cast<Body*>(item); 0267 if(body) _bodies.push_back(body); 0268 } 0269 */ 0270 0271 /*void World::removeItem(Item* item) 0272 { 0273 const ItemList::const_iterator it_end = _items.end(); 0274 for(ItemList::iterator it = _items.begin(); it != it_end; ++it) 0275 (*it)->worldItemRemoved(item); 0276 0277 item->setWorld(NULL); 0278 0279 ItemList::iterator i = std::find(_items.begin(), _items.end(), item); 0280 STEPCORE_ASSERT_NOABORT(i != _items.end()); 0281 _items.erase(i); 0282 0283 Force* force = dynamic_cast<Force*>(item); 0284 if(force) { 0285 ForceList::iterator f = std::find(_forces.begin(), _forces.end(), force); 0286 STEPCORE_ASSERT_NOABORT(f != _forces.end()); 0287 _forces.erase(f); 0288 } 0289 0290 Body* body = dynamic_cast<Body*>(item); 0291 if(body) { 0292 BodyList::iterator b = std::find(_bodies.begin(), _bodies.end(), body); 0293 STEPCORE_ASSERT_NOABORT(b != _bodies.end()); 0294 _bodies.erase(b); 0295 } 0296 } 0297 */ 0298 0299 /* 0300 int World::itemIndex(const Item* item) const 0301 { 0302 ItemList::const_iterator o = std::find(_items.begin(), _items.end(), item); 0303 STEPCORE_ASSERT_NOABORT(o != _items.end()); 0304 return std::distance(_items.begin(), o); 0305 } 0306 */ 0307 0308 /* 0309 Item* World::item(const QString& name) const 0310 { 0311 for(ItemList::const_iterator o = _items.begin(); o != _items.end(); ++o) { 0312 if((*o)->name() == name) return *o; 0313 } 0314 return NULL; 0315 } 0316 */ 0317 0318 Object* World::object(const QString& name) 0319 { 0320 if(name.isEmpty()) return nullptr; 0321 if(this->name() == name) return this; 0322 else if(_solver && _solver->name() == name) return _solver; 0323 else if(_collisionSolver && _collisionSolver->name() == name) return _collisionSolver; 0324 else if(_constraintSolver && _constraintSolver->name() == name) return _constraintSolver; 0325 else return item(name); 0326 } 0327 0328 void World::setSolver(Solver* solver) 0329 { 0330 delete _solver; 0331 _solver = solver; 0332 if(_solver != nullptr) { 0333 _solver->setDimension(_variablesCount*2); 0334 _solver->setFunction(solverFunction); 0335 _solver->setParams(this); 0336 } 0337 } 0338 0339 Solver* World::removeSolver() 0340 { 0341 Solver* solver = _solver; 0342 _solver = nullptr; 0343 return solver; 0344 } 0345 0346 void World::setCollisionSolver(CollisionSolver* collisionSolver) 0347 { 0348 delete _collisionSolver; 0349 _collisionSolver = collisionSolver; 0350 } 0351 0352 CollisionSolver* World::removeCollisionSolver() 0353 { 0354 CollisionSolver* collisionSolver = _collisionSolver; 0355 _collisionSolver = nullptr; 0356 return collisionSolver; 0357 } 0358 0359 void World::setConstraintSolver(ConstraintSolver* constraintSolver) 0360 { 0361 delete _constraintSolver; 0362 _constraintSolver = constraintSolver; 0363 } 0364 0365 ConstraintSolver* World::removeConstraintSolver() 0366 { 0367 ConstraintSolver* constraintSolver = _constraintSolver; 0368 _constraintSolver = nullptr; 0369 return constraintSolver; 0370 } 0371 0372 void World::checkVariablesCount() 0373 { 0374 int variablesCount = 0; 0375 for(BodyList::iterator b = _bodies.begin(); b != _bodies.end(); ++b) { 0376 (*b)->setVariablesOffset(variablesCount); 0377 variablesCount += (*b)->variablesCount(); 0378 } 0379 0380 int constraintsCount = 0; 0381 for(JointList::iterator j = _joints.begin(); j != _joints.end(); ++j) { 0382 constraintsCount += (*j)->constraintsCount(); 0383 } 0384 0385 _constraintsInfo.setDimension(variablesCount, constraintsCount, 0); 0386 0387 if(variablesCount != _variablesCount) { 0388 _variablesCount = variablesCount; 0389 _variables.resize(_variablesCount*2); 0390 _variances.resize(_variablesCount*2); 0391 _tempArray.resize(_variablesCount*2); 0392 if(_solver) _solver->setDimension(_variablesCount*2); 0393 } 0394 } 0395 0396 void World::gatherAccelerations(double* acceleration, double* accelerationVariance) 0397 { 0398 if(accelerationVariance) 0399 memset(accelerationVariance, 0, _variablesCount*sizeof(*accelerationVariance)); 0400 0401 int index = 0; 0402 const BodyList::const_iterator it_end = _bodies.end(); 0403 for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) { 0404 (*b)->getAccelerations(acceleration + index, accelerationVariance ? accelerationVariance + index : nullptr); 0405 index += (*b)->variablesCount(); 0406 } 0407 } 0408 0409 void World::gatherVariables(double* variables, double* variances) 0410 { 0411 if(variances) memset(variances, 0, _variablesCount*2*sizeof(*variances)); 0412 0413 int index = 0; 0414 const BodyList::const_iterator it_end = _bodies.end(); 0415 for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) { 0416 (*b)->getVariables(variables + index, variables + _variablesCount + index, 0417 variances ? variances + index : nullptr, 0418 variances ? variances + _variablesCount + index : nullptr); 0419 index += (*b)->variablesCount(); 0420 } 0421 } 0422 0423 void World::scatterVariables(const double* variables, const double* variances) 0424 { 0425 int index = 0; 0426 const BodyList::const_iterator it_end = _bodies.end(); 0427 for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) { 0428 (*b)->setVariables(variables + index, variables + _variablesCount + index, 0429 variances ? variances + index : nullptr, 0430 variances ? variances + _variablesCount + index : nullptr); 0431 index += (*b)->variablesCount(); 0432 } 0433 } 0434 0435 void World::gatherJointsInfo(ConstraintsInfo* info) 0436 { 0437 info->clear(); 0438 0439 int offset = 0; 0440 const BodyList::const_iterator b_end = _bodies.end(); 0441 for(BodyList::iterator body = _bodies.begin(); body != b_end; ++body) { 0442 (*body)->getInverseMass(&(info->inverseMass), nullptr, offset); 0443 offset += (*body)->variablesCount(); 0444 } 0445 0446 offset = 0; 0447 const JointList::const_iterator j_end = _joints.end(); 0448 for(JointList::iterator joint = _joints.begin(); joint != j_end; ++joint) { 0449 (*joint)->getConstraintsInfo(info, offset); 0450 offset += (*joint)->constraintsCount(); 0451 } 0452 } 0453 0454 int World::doCalcFn() 0455 { 0456 STEPCORE_ASSERT_NOABORT(_solver != nullptr); 0457 0458 //if(_collisionSolver) _collisionSolver->resetCaches(); 0459 0460 _stopOnCollision = false; 0461 _stopOnIntersection = false; 0462 checkVariablesCount(); 0463 gatherVariables(_variables.data(), _errorsCalculation ? _variances.data() : nullptr); 0464 return _solver->doCalcFn(&_time, &_variables, _errorsCalculation ? &_variances : nullptr, 0465 nullptr, _errorsCalculation ? &_variances : nullptr); 0466 } 0467 0468 int World::doEvolve(double delta) 0469 { 0470 STEPCORE_ASSERT_NOABORT(_solver != nullptr); 0471 0472 checkVariablesCount(); 0473 gatherVariables(_variables.data(), _errorsCalculation ? _variances.data() : nullptr); 0474 0475 int ret = Solver::OK; 0476 double targetTime = _time + delta*_timeScale; 0477 0478 if(_collisionSolver) { 0479 //_collisionSolver->resetCaches(); 0480 if(Contact::Intersected == _collisionSolver->checkContacts(_bodies)) 0481 return Solver::IntersectionDetected; 0482 } 0483 0484 while(_time < targetTime) { 0485 STEPCORE_ASSERT_NOABORT( targetTime - _time > _solver->stepSize() / 1000 ); 0486 if( !( targetTime - _time > _solver->stepSize() / 1000 ) ) { 0487 qDebug("* %e %e %e", targetTime, _time, _solver->stepSize()); 0488 } 0489 double time = _time; 0490 0491 _stopOnCollision = true; 0492 _stopOnIntersection = true; 0493 0494 ret = _solver->doEvolve(&time, targetTime, &_variables, 0495 _errorsCalculation ? &_variances : nullptr); 0496 0497 _time = time; 0498 0499 if(ret == Solver::CollisionDetected || 0500 ret == Solver::IntersectionDetected) { 0501 // If we have stopped on collision 0502 // 1. Decrease timestep to stop before collision 0503 // 2. Proceed with decreased timestep until 0504 // - we have meet collision again: go to 1 0505 // - we pass collision point: it means that we have come close enough 0506 // to collision point and CollisionSolver have resolved collision 0507 // We can't simply change Solver::stepSize since adaptive solvers can 0508 // abuse our settings so we have to step manually 0509 //STEPCORE_ASSERT_NOABORT(_collisionTime <= targetTime); 0510 //STEPCORE_ASSERT_NOABORT(_collisionTime > _time); 0511 double stepSize = fmin(_solver->stepSize() / 2, targetTime - _time); 0512 double collisionEndTime = targetTime - _time > stepSize*3.01 ? _time + stepSize*3 : targetTime; 0513 0514 _stopOnCollision = false; 0515 0516 do { 0517 double endTime = collisionEndTime - time > stepSize*1.01 ? time+stepSize : collisionEndTime; 0518 0519 ret = _solver->doEvolve(&time, endTime, &_variables, 0520 _errorsCalculation ? &_variances : nullptr); 0521 0522 _time = time; 0523 0524 if(ret == Solver::IntersectionDetected || ret == Solver::CollisionDetected) { 0525 //STEPCORE_ASSERT_NOABORT(_collisionTime > _time); 0526 //STEPCORE_ASSERT_NOABORT(_collisionTime < _collisionExpectedTime); 0527 stepSize = fmin(stepSize/2, targetTime - _time); 0528 collisionEndTime = targetTime - _time > stepSize*3.01 ? _time + stepSize*3 : targetTime; 0529 0530 //STEPCORE_ASSERT_NOABORT(_time + stepSize != _time); 0531 // XXX: what to do if stepSize becomes too small ? 0532 0533 } else if(ret == Solver::OK) { 0534 // We can be close to the collision point. 0535 // 0536 // Now we will calculate impulses required to fix collisions. 0537 // All joints should be taken into account, but since we are 0538 // calculating impulses we should "froze" the jacobian i.e. 0539 // ignore it derivative 0540 scatterVariables(_variables.data(), _errorsCalculation ? _variances.data() : nullptr); 0541 0542 // check and count contacts before the sparse matrix assembly 0543 int contactsCount = 0; 0544 int status = _collisionSolver->checkContacts(_bodies, true, &contactsCount); 0545 if (contactsCount!=_constraintsInfo.contactsCount) 0546 { 0547 _constraintsInfo.setDimension(_constraintsInfo.variablesCount, 0548 _constraintsInfo.constraintsCount, 0549 contactsCount); 0550 } 0551 0552 _tempArray.setZero(); 0553 ::new (&_constraintsInfo.position) MappedVector(_variables.data(), _variablesCount); 0554 ::new (&_constraintsInfo.velocity) MappedVector(_variables.data()+_variablesCount, _variablesCount); 0555 ::new (&_constraintsInfo.acceleration) MappedVector(_tempArray.data(), _variablesCount); 0556 0557 // start sparse matrix assembly 0558 gatherJointsInfo(&_constraintsInfo); 0559 _constraintsInfo.jacobianDerivative.setZero(); 0560 0561 if(status >= CollisionSolver::InternalError) { ret = status; goto out; } 0562 0563 _collisionSolver->getContactsInfo(_constraintsInfo, true); 0564 // end sparse matrix assembly 0565 0566 if(_constraintsInfo.collisionFlag) { 0567 ret = _constraintSolver->solve(&_constraintsInfo); 0568 if(ret != Solver::OK) goto out; 0569 0570 // XXX: variances 0571 _constraintsInfo.velocity += _constraintsInfo.inverseMass.asDiagonal() * _constraintsInfo.force; 0572 } 0573 } else goto out; 0574 0575 } while(_time + stepSize/100 <= collisionEndTime); // XXX 0576 } else if(ret != Solver::OK) goto out; 0577 } 0578 0579 out: 0580 scatterVariables(_variables.data(), _errorsCalculation ? _variances.data() : nullptr); 0581 return ret; 0582 } 0583 0584 inline int World::solverFunction(double t, const double* y, 0585 const double* yvar, double* f, double* fvar) 0586 { 0587 if(_evolveAbort) return Solver::Aborted; 0588 0589 _time = t; 0590 scatterVariables(y, yvar); // this will reset force 0591 0592 // 1. Forces 0593 bool calcVariances = (fvar != nullptr); 0594 const ForceList::const_iterator f_end = _forces.end(); 0595 for(ForceList::iterator force = _forces.begin(); force != f_end; ++force) { 0596 (*force)->calcForce(calcVariances); 0597 } 0598 0599 std::memcpy(f, y+_variablesCount, _variablesCount*sizeof(*f)); 0600 if(fvar) std::memcpy(fvar, y+_variablesCount, _variablesCount*sizeof(*fvar)); 0601 gatherAccelerations(f+_variablesCount, fvar ? fvar+_variablesCount : nullptr); 0602 0603 if (_constraintSolver) 0604 { 0605 // setup... 0606 0607 // check contacts 0608 int state = 0; 0609 if(_collisionSolver) { 0610 int contactsCount = 0; 0611 state = _collisionSolver->checkContacts(_bodies, false, &contactsCount); 0612 0613 if (contactsCount!=_constraintsInfo.contactsCount) 0614 { 0615 _constraintsInfo.setDimension(_constraintsInfo.variablesCount, 0616 _constraintsInfo.constraintsCount, 0617 contactsCount); 0618 } 0619 } 0620 0621 if(_variablesCount>0) 0622 { 0623 ::new (&_constraintsInfo.position) Eigen::Map<const Eigen::VectorXd>(y, _variablesCount); 0624 ::new (&_constraintsInfo.velocity) Eigen::Map<const Eigen::VectorXd>(y+_variablesCount, _variablesCount); 0625 ::new (&_constraintsInfo.acceleration) Eigen::Map<Eigen::VectorXd>(f+_variablesCount, _variablesCount); 0626 } 0627 0628 // end sparse matrix assembly 0629 0630 // 2. Joints 0631 gatherJointsInfo(&_constraintsInfo); 0632 0633 // 3. Collisions (TODO: variances for collisions) 0634 if(_collisionSolver) { 0635 _collisionSolver->getContactsInfo(_constraintsInfo, false); 0636 if(state == Contact::Intersected) { 0637 if(_stopOnIntersection) return Solver::IntersectionDetected; 0638 } else { 0639 if(state == Contact::Colliding) { 0640 if(_stopOnCollision) return Solver::CollisionDetected; 0641 // XXX: We are not stopping on colliding contact 0642 // and resolving them only at the end of timestep 0643 // XXX: is it right solution ? Shouldn't we try to find 0644 // contact point more exactly for example using binary search ? 0645 //_collisionTime = t; 0646 //_collisionTime = t; 0647 //if(t < _collisionExpectedTime) 0648 // return DantzigLCPCollisionSolver::CollisionDetected; 0649 } else if(state >= CollisionSolver::InternalError) { 0650 return state; 0651 } 0652 } 0653 } 0654 // end sparse matrix assembly 0655 0656 // 4. Solve constraints 0657 if(_constraintsInfo.constraintsCount + _constraintsInfo.contactsCount > 0) { 0658 0659 int state = _constraintSolver->solve(&_constraintsInfo); 0660 if(state != Solver::OK) return state; 0661 0662 int offset = 0; 0663 const BodyList::const_iterator b_end = _bodies.end(); 0664 for(BodyList::iterator body = _bodies.begin(); body != b_end; ++body) { 0665 (*body)->addForce(&_constraintsInfo.force[offset], nullptr); 0666 (*body)->getAccelerations(f+_variablesCount+offset, nullptr); 0667 offset += (*body)->variablesCount(); 0668 } 0669 } 0670 } 0671 0672 return 0; 0673 } 0674 0675 int World::solverFunction(double t, const double* y, 0676 const double* yvar, double* f, double* fvar, void* params) 0677 { 0678 return static_cast<World*>(params)->solverFunction(t, y, yvar, f, fvar); 0679 } 0680 0681 } // namespace StepCore 0682