• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

step/stepcore

  • sources
  • kde-4.12
  • kdeedu
  • step
  • stepcore
world.cc
Go to the documentation of this file.
1 /* This file is part of StepCore library.
2  Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 
4  StepCore library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  StepCore library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with StepCore; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "world.h"
20 #include "solver.h"
21 #include "collisionsolver.h"
22 #include "constraintsolver.h"
23 #include <algorithm>
24 #include <cmath>
25 #include <QtGlobal>
26 
27 namespace StepCore
28 {
29 
30 STEPCORE_META_OBJECT(Item, QT_TRANSLATE_NOOP("ObjectClass", "Item"), QT_TR_NOOP("Item"), MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object),
31  STEPCORE_PROPERTY_RW(StepCore::Color, color, QT_TRANSLATE_NOOP("PropertyName", "color"), STEPCORE_UNITS_NULL, QT_TR_NOOP("Item color"), color, setColor))
32 STEPCORE_META_OBJECT(Body, QT_TRANSLATE_NOOP("ObjectClass", "Body"), QT_TR_NOOP("Body"), MetaObject::ABSTRACT,,)
33 STEPCORE_META_OBJECT(Force, QT_TRANSLATE_NOOP("ObjectClass", "Force"), QT_TR_NOOP("Force"), MetaObject::ABSTRACT,,)
34 STEPCORE_META_OBJECT(Joint, QT_TRANSLATE_NOOP("ObjectClass", "Joint"), QT_TR_NOOP("Joint"), MetaObject::ABSTRACT,,)
35 STEPCORE_META_OBJECT(Tool, QT_TRANSLATE_NOOP("ObjectClass", "Tool"), QT_TR_NOOP("Tool"), MetaObject::ABSTRACT,,)
36 
37 STEPCORE_META_OBJECT(ObjectErrors, QT_TRANSLATE_NOOP("ObjectClass", "ObjectErrors"), QT_TR_NOOP("ObjectErrors"), MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object),)
38 
39 STEPCORE_META_OBJECT(ItemGroup, QT_TRANSLATE_NOOP("ObjectClass", "ItemGroup"), QT_TR_NOOP("ItemGroup"), 0, STEPCORE_SUPER_CLASS(Item),)
40 
41 STEPCORE_META_OBJECT(World, QT_TRANSLATE_NOOP("ObjectClass", "World"), QT_TR_NOOP("World"), 0, STEPCORE_SUPER_CLASS(ItemGroup),
42  STEPCORE_PROPERTY_RW_D(double, time, QT_TRANSLATE_NOOP("PropertyName", "time"), QT_TRANSLATE_NOOP("Units", "s"), QT_TR_NOOP("Current time"), time, setTime)
43  STEPCORE_PROPERTY_RW (double, timeScale, QT_TR_NOOP("timeScale"), STEPCORE_UNITS_1, QT_TR_NOOP("Simulation speed scale"), timeScale, setTimeScale)
44  STEPCORE_PROPERTY_RW (bool, errorsCalculation, QT_TR_NOOP("errorsCalculation"), STEPCORE_UNITS_NULL,
45  QT_TR_NOOP("Enable global error calculation"), errorsCalculation, setErrorsCalculation))
46 
47 Item& Item::operator=(const Item& item)
48 {
49  Object::operator=(item);
50 
51  _world = item._world;
52  _group = item._group;
53 
54  if(item._objectErrors) {
55  _objectErrors = static_cast<ObjectErrors*>(
56  item._objectErrors->metaObject()->cloneObject(*item._objectErrors) );
57  _objectErrors->setOwner(this);
58  } else {
59  _objectErrors = NULL;
60  }
61 
62  _color = item._color;
63 
64  return *this;
65 }
66 
67 ObjectErrors* Item::objectErrors()
68 {
69  if(!_objectErrors) _objectErrors = createObjectErrors();
70  return _objectErrors;
71 }
72 
73 ItemGroup::ItemGroup(const ItemGroup& group)
74  : Item()
75 {
76  *this = group;
77 }
78 
79 void ItemGroup::setWorld(World* world)
80 {
81  ItemList::const_iterator end = _items.end();
82  for(ItemList::const_iterator it = _items.begin(); it != end; ++it)
83  (*it)->setWorld(world);
84  Item::setWorld(world);
85 }
86 
87 void ItemGroup::worldItemRemoved(Item* item)
88 {
89  ItemList::const_iterator end = _items.end();
90  for(ItemList::const_iterator it = _items.begin(); it != end; ++it)
91  (*it)->worldItemRemoved(item);
92 }
93 
94 void ItemGroup::addItem(Item* item)
95 {
96  _items.push_back(item);
97 
98  if(world()) world()->worldItemAdded(item);
99 
100  item->setGroup(this);
101  item->setWorld(this->world());
102 }
103 
104 void ItemGroup::removeItem(Item* item)
105 {
106  item->setWorld(NULL);
107  item->setGroup(NULL);
108 
109  if(world()) world()->worldItemRemoved(item);
110 
111  ItemList::iterator i = std::find(_items.begin(), _items.end(), item);
112  STEPCORE_ASSERT_NOABORT(i != _items.end());
113  _items.erase(i);
114 }
115 
116 void ItemGroup::clear()
117 {
118  ItemList::const_iterator end = _items.end();
119  for(ItemList::const_iterator it = _items.begin(); it != end; ++it) {
120  (*it)->setWorld(NULL);
121  (*it)->setGroup(NULL);
122  if(world()) world()->worldItemRemoved(*it);
123  }
124 
125  for(ItemList::const_iterator it = _items.begin(); it != end; ++it) {
126  delete *it;
127  }
128 
129  _items.clear();
130 }
131 
132 ItemGroup::~ItemGroup()
133 {
134  clear();
135 }
136 
137 ItemGroup& ItemGroup::operator=(const ItemGroup& group)
138 {
139 
140  /*
141  item->setGroup(this);
142  item->setWorld(this->world());
143  _items.push_back(item);
144 
145  if(world()) {
146  //world()->worldItemAdded(item);
147  ItemGroup* gr = dynamic_cast<ItemGroup*>(item);
148  if(gr) gr->groupItemsAdded();
149  }
150  */
151 
152  if(this == &group) return *this;
153 
154  clear();
155 
156  _items.reserve(group._items.size());
157 
158  const ItemList::const_iterator gr_end = group._items.end();
159  for(ItemList::const_iterator it = group._items.begin(); it != gr_end; ++it) {
160  StepCore::Item* item = static_cast<Item*>( (*it)->metaObject()->cloneObject(*(*it)) );
161  _items.push_back(item);
162  }
163 
164  const ItemList::const_iterator end = _items.end();
165  for(ItemList::const_iterator it = _items.begin(); it != end; ++it) {
166  (*it)->setGroup(this);
167  }
168 
169  Item::operator=(group);
170 
171  // NOTE: We don't change world() here
172 
173  return *this;
174 }
175 
176 int ItemGroup::childItemIndex(const Item* item) const
177 {
178  ItemList::const_iterator o = std::find(_items.begin(), _items.end(), item);
179  STEPCORE_ASSERT_NOABORT(o != _items.end());
180  return std::distance(_items.begin(), o);
181 }
182 
183 Item* ItemGroup::childItem(const QString& name) const
184 {
185  ItemList::const_iterator end = _items.end();
186  for(ItemList::const_iterator it = _items.begin(); it != end; ++it)
187  if((*it)->name() == name) return *it;
188  return NULL;
189 }
190 
191 Item* ItemGroup::item(const QString& name) const
192 {
193  if(name.isEmpty()) return NULL;
194  ItemList::const_iterator end = _items.end();
195  for(ItemList::const_iterator it = _items.begin(); it != end; ++it) {
196  if((*it)->name() == name) return *it;
197  if((*it)->metaObject()->inherits<ItemGroup>()) {
198  Item* ret = static_cast<ItemGroup*>(*it)->item(name);
199  if(ret) return ret;
200  }
201  }
202  return NULL;
203 }
204 
205 void ItemGroup::allItems(ItemList* items) const
206 {
207  items->reserve(_items.size());
208  ItemList::const_iterator end = _items.end();
209  for(ItemList::const_iterator it = _items.begin(); it != end; ++it) {
210  items->push_back(*it);
211  if((*it)->metaObject()->inherits<ItemGroup>())
212  static_cast<ItemGroup*>(*it)->allItems(items);
213  }
214 }
215 
216 void ConstraintsInfo::setDimension(int newVariablesCount, int newConstraintsCount, int newContactsCount)
217 {
218 // std::cerr << " ConstraintsInfo::setDimension("
219 // << newVariablesCount <<","<< newConstraintsCount <<"," << newContactsCount << ")\n";
220 
221  int totalConstraintsCount = newConstraintsCount+newContactsCount;
222 
223  jacobian.resize(totalConstraintsCount, newVariablesCount);
224  jacobianDerivative.resize(totalConstraintsCount, newVariablesCount);
225  inverseMass.resize(newVariablesCount);
226  force.resize(newVariablesCount);
227  value.resize(totalConstraintsCount);
228  derivative.resize(totalConstraintsCount);
229  if (totalConstraintsCount>0)
230  {
231  derivative.setZero();
232  value.setZero();
233  }
234  forceMin.resize(totalConstraintsCount);
235  forceMax.resize(totalConstraintsCount);
236 
237  contactsCount = newContactsCount;
238  constraintsCount = newConstraintsCount;
239  variablesCount = newVariablesCount;
240 }
241 
242 void ConstraintsInfo::clear()
243 {
244  jacobian.setZero();
245  jacobianDerivative.setZero();
246  if(inverseMass.size()>0)
247  {
248  inverseMass.setZero();
249  }
250  if(forceMin.size()>0)
251  {
252  forceMin.fill(-HUGE_VAL);
253  forceMax.fill(HUGE_VAL);
254  }
255 
256  collisionFlag = false;
257 }
258 
259 World::World()
260  : _time(0), _timeScale(1), _errorsCalculation(false),
261  _solver(NULL), _collisionSolver(NULL), _constraintSolver(NULL),
262  _variablesCount(0)
263 {
264  setColor(0xffffffff);
265  setWorld(this);
266  clear();
267 }
268 
269 World::World(const World& world)
270  : ItemGroup(), _time(0), _timeScale(1), _errorsCalculation(false),
271  _solver(NULL), _collisionSolver(NULL), _constraintSolver(NULL),
272  _variablesCount(0)
273 {
274  *this = world;
275 }
276 
277 World::~World()
278 {
279  clear();
280 }
281 
282 void World::clear()
283 {
284  // Avoid erasing each element individually in the cache
285  if(_collisionSolver) _collisionSolver->resetCaches();
286 
287  // clear _items
288  ItemGroup::clear();
289 
290  STEPCORE_ASSERT_NOABORT(_bodies.empty());
291  STEPCORE_ASSERT_NOABORT(_forces.empty());
292  STEPCORE_ASSERT_NOABORT(_joints.empty());
293  //_bodies.clear();
294  //_forces.clear();
295 
296  delete _solver; _solver = NULL;
297  delete _collisionSolver; _collisionSolver = NULL;
298  delete _constraintSolver; _constraintSolver = NULL;
299 
300  _variablesCount = 0;
301  _variables.resize(0);
302  _variances.resize(0);
303  _tempArray.resize(0);
304 
305  _constraintsInfo.setDimension(0, 0);
306 
307  setColor(0xffffffff);
308  deleteObjectErrors();
309 
310  _time = 0;
311  _timeScale = 1;
312  _errorsCalculation = false;
313 
314  _stopOnCollision = false;
315  _stopOnIntersection = false;
316  _evolveAbort = false;
317 
318 #ifdef STEPCORE_WITH_QT
319  setName(QString());
320 #endif
321 }
322 
323 World& World::operator=(const World& world)
324 {
325  if(this == &world) return *this;
326 
327  clear();
328  ItemGroup::operator=(world);
329 
330  if(world._solver) {
331  setSolver(static_cast<Solver*>(
332  world._solver->metaObject()->cloneObject(*(world._solver))));
333  } else setSolver(0);
334 
335  if(world._collisionSolver) {
336  setCollisionSolver(static_cast<CollisionSolver*>(
337  world._collisionSolver->metaObject()->cloneObject(*(world._collisionSolver))));
338  } else setCollisionSolver(0);
339 
340  if(world._constraintSolver) setConstraintSolver(static_cast<ConstraintSolver*>(
341  world._constraintSolver->metaObject()->cloneObject(*(world._constraintSolver))));
342  else setConstraintSolver(0);
343 
344  _time = world._time;
345  _timeScale = world._timeScale;
346  _errorsCalculation = world._errorsCalculation;
347 
348  _stopOnCollision = world._stopOnCollision;
349  _stopOnIntersection = world._stopOnIntersection;
350  _evolveAbort = world._evolveAbort;
351 
352  // Fix links
353  QHash<const Object*, Object*> copyMap;
354  copyMap.insert(NULL, NULL);
355  copyMap.insert(&world, this);
356  if(_solver) copyMap.insert(world._solver, _solver);
357  if(_collisionSolver) copyMap.insert(world._collisionSolver, _collisionSolver);
358  if(_constraintSolver) copyMap.insert(world._constraintSolver, _constraintSolver);
359  fillCopyMap(&copyMap, &world, this);
360 
361  applyCopyMap(&copyMap, this);
362  if(_solver) applyCopyMap(&copyMap, _solver);
363  if(_collisionSolver) applyCopyMap(&copyMap, _collisionSolver);
364  if(_constraintSolver) applyCopyMap(&copyMap, _constraintSolver);
365 
366  const ItemList::const_iterator end = items().end();
367  for(ItemList::const_iterator it = items().begin(); it != end; ++it) {
368  worldItemCopied(&copyMap, *it);
369  }
370 
371  setWorld(this);
372 
373  checkVariablesCount();
374 
375  return *this;
376 }
377 
378 void World::fillCopyMap(QHash<const Object*, Object*>* map,
379  const ItemGroup* g1, ItemGroup* g2)
380 {
381  const ItemList::const_iterator end = g1->items().end();
382  for(ItemList::const_iterator it1 = g1->items().begin(),
383  it2 = g2->items().begin();
384  it1 != end; ++it1, ++it2) {
385  map->insert(*it1, *it2);
386  if((*it1)->metaObject()->inherits<StepCore::ItemGroup>())
387  fillCopyMap(map, static_cast<ItemGroup*>(*it1), static_cast<ItemGroup*>(*it2));
388  }
389 }
390 
391 void World::applyCopyMap(QHash<const Object*, Object*>* map, Object* obj)
392 {
393  const StepCore::MetaObject* mobj = obj->metaObject();
394  for(int i=0; i<mobj->propertyCount(); ++i) {
395  const StepCore::MetaProperty* pr = mobj->property(i);
396  if(pr->userTypeId() == qMetaTypeId<Object*>()) {
397  QVariant v = pr->readVariant(obj);
398  v = QVariant::fromValue(map->value(v.value<Object*>(), NULL));
399  pr->writeVariant(obj, v);
400  }
401  }
402 }
403 
404 void World::worldItemCopied(QHash<const Object*, Object*>* map, Item* item)
405 {
406  applyCopyMap(map, item);
407 
408  if(item->metaObject()->inherits<Force>())
409  _forces.push_back(dynamic_cast<Force*>(item));
410  if(item->metaObject()->inherits<Joint>())
411  _joints.push_back(dynamic_cast<Joint*>(item));
412  if(item->metaObject()->inherits<Body>())
413  _bodies.push_back(dynamic_cast<Body*>(item));
414 
415  if(item->metaObject()->inherits<ItemGroup>()) {
416  ItemGroup* group = static_cast<ItemGroup*>(item);
417  ItemList::const_iterator end = group->items().end();
418  for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) {
419  worldItemCopied(map, *it);
420  }
421  }
422 }
423 
424 void World::worldItemAdded(Item* item)
425 {
426  if(item->metaObject()->inherits<Force>())
427  _forces.push_back(dynamic_cast<Force*>(item));
428 
429  if(item->metaObject()->inherits<Joint>())
430  _joints.push_back(dynamic_cast<Joint*>(item));
431 
432  if(item->metaObject()->inherits<Body>()) {
433  Body* body = dynamic_cast<Body*>(item);
434  _bodies.push_back(body);
435  if(_collisionSolver) _collisionSolver->bodyAdded(_bodies, body);
436  }
437 
438  if(item->metaObject()->inherits<ItemGroup>()) {
439  ItemGroup* group = static_cast<ItemGroup*>(item);
440  ItemList::const_iterator end = group->items().end();
441  for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) {
442  worldItemAdded(*it);
443  }
444  }
445 
446  checkVariablesCount();
447 }
448 
449 void World::worldItemRemoved(Item* item)
450 {
451  if(item->metaObject()->inherits<ItemGroup>()) {
452  ItemGroup* group = static_cast<ItemGroup*>(item);
453  ItemList::const_iterator end = group->items().end();
454  for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) {
455  worldItemRemoved(*it);
456  }
457  }
458 
459  const ItemList::const_iterator end = items().end();
460  for(ItemList::const_iterator it = items().begin(); it != end; ++it) {
461  (*it)->worldItemRemoved(item);
462  }
463 
464  if(item->metaObject()->inherits<Body>()) {
465  Body* body = dynamic_cast<Body*>(item);
466  if(_collisionSolver) _collisionSolver->bodyRemoved(_bodies, body);
467  BodyList::iterator b = std::find(_bodies.begin(), _bodies.end(), body);
468  STEPCORE_ASSERT_NOABORT(b != _bodies.end());
469  _bodies.erase(b);
470  }
471 
472  if(item->metaObject()->inherits<Joint>()) {
473  JointList::iterator j = std::find(_joints.begin(), _joints.end(),
474  dynamic_cast<Joint*>(item));
475  STEPCORE_ASSERT_NOABORT(j != _joints.end());
476  _joints.erase(j);
477  }
478 
479  if(item->metaObject()->inherits<Force>()) {
480  ForceList::iterator f = std::find(_forces.begin(), _forces.end(),
481  dynamic_cast<Force*>(item));
482  STEPCORE_ASSERT_NOABORT(f != _forces.end());
483  _forces.erase(f);
484  }
485 
486  // XXX: on ItemGroup::clear this will be called on each object !
487  checkVariablesCount();
488 }
489 
490 /*
491 void World::addItem(Item* item)
492 {
493  _items.push_back(item);
494  item->setWorld(this);
495  Force* force = dynamic_cast<Force*>(item);
496  if(force) _forces.push_back(force);
497  Body* body = dynamic_cast<Body*>(item);
498  if(body) _bodies.push_back(body);
499 }
500 */
501 
502 /*void World::removeItem(Item* item)
503 {
504  const ItemList::const_iterator it_end = _items.end();
505  for(ItemList::iterator it = _items.begin(); it != it_end; ++it)
506  (*it)->worldItemRemoved(item);
507 
508  item->setWorld(NULL);
509 
510  ItemList::iterator i = std::find(_items.begin(), _items.end(), item);
511  STEPCORE_ASSERT_NOABORT(i != _items.end());
512  _items.erase(i);
513 
514  Force* force = dynamic_cast<Force*>(item);
515  if(force) {
516  ForceList::iterator f = std::find(_forces.begin(), _forces.end(), force);
517  STEPCORE_ASSERT_NOABORT(f != _forces.end());
518  _forces.erase(f);
519  }
520 
521  Body* body = dynamic_cast<Body*>(item);
522  if(body) {
523  BodyList::iterator b = std::find(_bodies.begin(), _bodies.end(), body);
524  STEPCORE_ASSERT_NOABORT(b != _bodies.end());
525  _bodies.erase(b);
526  }
527 }
528 */
529 
530 /*
531 int World::itemIndex(const Item* item) const
532 {
533  ItemList::const_iterator o = std::find(_items.begin(), _items.end(), item);
534  STEPCORE_ASSERT_NOABORT(o != _items.end());
535  return std::distance(_items.begin(), o);
536 }
537 */
538 
539 /*
540 Item* World::item(const QString& name) const
541 {
542  for(ItemList::const_iterator o = _items.begin(); o != _items.end(); ++o) {
543  if((*o)->name() == name) return *o;
544  }
545  return NULL;
546 }
547 */
548 
549 Object* World::object(const QString& name)
550 {
551  if(name.isEmpty()) return NULL;
552  if(this->name() == name) return this;
553  else if(_solver && _solver->name() == name) return _solver;
554  else if(_collisionSolver && _collisionSolver->name() == name) return _collisionSolver;
555  else if(_constraintSolver && _constraintSolver->name() == name) return _constraintSolver;
556  else return item(name);
557 }
558 
559 void World::setSolver(Solver* solver)
560 {
561  delete _solver;
562  _solver = solver;
563  if(_solver != 0) {
564  _solver->setDimension(_variablesCount*2);
565  _solver->setFunction(solverFunction);
566  _solver->setParams(this);
567  }
568 }
569 
570 Solver* World::removeSolver()
571 {
572  Solver* solver = _solver;
573  _solver = NULL;
574  return solver;
575 }
576 
577 void World::setCollisionSolver(CollisionSolver* collisionSolver)
578 {
579  delete _collisionSolver;
580  _collisionSolver = collisionSolver;
581 }
582 
583 CollisionSolver* World::removeCollisionSolver()
584 {
585  CollisionSolver* collisionSolver = _collisionSolver;
586  _collisionSolver = NULL;
587  return collisionSolver;
588 }
589 
590 void World::setConstraintSolver(ConstraintSolver* constraintSolver)
591 {
592  delete _constraintSolver;
593  _constraintSolver = constraintSolver;
594 }
595 
596 ConstraintSolver* World::removeConstraintSolver()
597 {
598  ConstraintSolver* constraintSolver = _constraintSolver;
599  _constraintSolver = NULL;
600  return constraintSolver;
601 }
602 
603 void World::checkVariablesCount()
604 {
605  int variablesCount = 0;
606  for(BodyList::iterator b = _bodies.begin(); b != _bodies.end(); ++b) {
607  (*b)->setVariablesOffset(variablesCount);
608  variablesCount += (*b)->variablesCount();
609  }
610 
611  int constraintsCount = 0;
612  for(JointList::iterator j = _joints.begin(); j != _joints.end(); ++j) {
613  constraintsCount += (*j)->constraintsCount();
614  }
615 
616  _constraintsInfo.setDimension(variablesCount, constraintsCount, 0);
617 
618  if(variablesCount != _variablesCount) {
619  _variablesCount = variablesCount;
620  _variables.resize(_variablesCount*2);
621  _variances.resize(_variablesCount*2);
622  _tempArray.resize(_variablesCount*2);
623  if(_solver) _solver->setDimension(_variablesCount*2);
624  }
625 }
626 
627 void World::gatherAccelerations(double* acceleration, double* accelerationVariance)
628 {
629  if(accelerationVariance)
630  memset(accelerationVariance, 0, _variablesCount*sizeof(*accelerationVariance));
631 
632  int index = 0;
633  const BodyList::const_iterator it_end = _bodies.end();
634  for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) {
635  (*b)->getAccelerations(acceleration + index, accelerationVariance ? accelerationVariance + index : NULL);
636  index += (*b)->variablesCount();
637  }
638 }
639 
640 void World::gatherVariables(double* variables, double* variances)
641 {
642  if(variances) memset(variances, 0, _variablesCount*2*sizeof(*variances));
643 
644  int index = 0;
645  const BodyList::const_iterator it_end = _bodies.end();
646  for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) {
647  (*b)->getVariables(variables + index, variables + _variablesCount + index,
648  variances ? variances + index : NULL,
649  variances ? variances + _variablesCount + index : NULL);
650  index += (*b)->variablesCount();
651  }
652 }
653 
654 void World::scatterVariables(const double* variables, const double* variances)
655 {
656  int index = 0;
657  const BodyList::const_iterator it_end = _bodies.end();
658  for(BodyList::iterator b = _bodies.begin(); b != it_end; ++b) {
659  (*b)->setVariables(variables + index, variables + _variablesCount + index,
660  variances ? variances + index : NULL,
661  variances ? variances + _variablesCount + index : NULL);
662  index += (*b)->variablesCount();
663  }
664 }
665 
666 void World::gatherJointsInfo(ConstraintsInfo* info)
667 {
668  info->clear();
669 
670  int offset = 0;
671  const BodyList::const_iterator b_end = _bodies.end();
672  for(BodyList::iterator body = _bodies.begin(); body != b_end; ++body) {
673  (*body)->getInverseMass(&(info->inverseMass), NULL, offset);
674  offset += (*body)->variablesCount();
675  }
676 
677  offset = 0;
678  const JointList::const_iterator j_end = _joints.end();
679  for(JointList::iterator joint = _joints.begin(); joint != j_end; ++joint) {
680  (*joint)->getConstraintsInfo(info, offset);
681  offset += (*joint)->constraintsCount();
682  }
683 }
684 
685 int World::doCalcFn()
686 {
687  STEPCORE_ASSERT_NOABORT(_solver != NULL);
688 
689  //if(_collisionSolver) _collisionSolver->resetCaches();
690 
691  _stopOnCollision = false;
692  _stopOnIntersection = false;
693  checkVariablesCount();
694  gatherVariables(_variables.data(), _errorsCalculation ? _variances.data() : NULL);
695  return _solver->doCalcFn(&_time, &_variables, _errorsCalculation ? &_variances : NULL,
696  NULL, _errorsCalculation ? &_variances : NULL);
697 }
698 
699 int World::doEvolve(double delta)
700 {
701  STEPCORE_ASSERT_NOABORT(_solver != NULL);
702 
703  checkVariablesCount();
704  gatherVariables(_variables.data(), _errorsCalculation ? _variances.data() : NULL);
705 
706  int ret = Solver::OK;
707  double targetTime = _time + delta*_timeScale;
708 
709  if(_collisionSolver) {
710  //_collisionSolver->resetCaches();
711  if(Contact::Intersected == _collisionSolver->checkContacts(_bodies))
712  return Solver::IntersectionDetected;
713  }
714 
715  while(_time < targetTime) {
716  STEPCORE_ASSERT_NOABORT( targetTime - _time > _solver->stepSize() / 1000 );
717  if( !( targetTime - _time > _solver->stepSize() / 1000 ) ) {
718  qDebug("* %e %e %e", targetTime, _time, _solver->stepSize());
719  }
720  double time = _time;
721 
722  _stopOnCollision = true;
723  _stopOnIntersection = true;
724 
725  ret = _solver->doEvolve(&time, targetTime, &_variables,
726  _errorsCalculation ? &_variances : NULL);
727 
728  _time = time;
729 
730  if(ret == Solver::CollisionDetected ||
731  ret == Solver::IntersectionDetected) {
732  // If we have stopped on collision
733  // 1. Decrease timestep to stop before collision
734  // 2. Proceed with decresed timestep until
735  // - we have meet collision again: go to 1
736  // - we pass collision point: it means that we have come close enough
737  // to collision point and CollisionSolver have resolved collision
738  // We can't simply change Solver::stepSize since adaptive solvers can
739  // abuse our settings so we have to step manually
740  //STEPCORE_ASSERT_NOABORT(_collisionTime <= targetTime);
741  //STEPCORE_ASSERT_NOABORT(_collisionTime > _time);
742  double stepSize = fmin(_solver->stepSize() / 2, targetTime - _time);
743  double collisionEndTime = targetTime - _time > stepSize*3.01 ? _time + stepSize*3 : targetTime;
744 
745  _stopOnCollision = false;
746 
747  do {
748  double endTime = collisionEndTime - time > stepSize*1.01 ? time+stepSize : collisionEndTime;
749 
750  ret = _solver->doEvolve(&time, endTime, &_variables,
751  _errorsCalculation ? &_variances : NULL);
752 
753  _time = time;
754 
755  if(ret == Solver::IntersectionDetected || ret == Solver::CollisionDetected) {
756  //STEPCORE_ASSERT_NOABORT(_collisionTime > _time);
757  //STEPCORE_ASSERT_NOABORT(_collisionTime < _collisionExpectedTime);
758  stepSize = fmin(stepSize/2, targetTime - _time);
759  collisionEndTime = targetTime - _time > stepSize*3.01 ? _time + stepSize*3 : targetTime;
760 
761  //STEPCORE_ASSERT_NOABORT(_time + stepSize != _time);
762  // XXX: what to do if stepSize becomes too small ?
763 
764  } else if(ret == Solver::OK) {
765  // We can be close to the collision point.
766  //
767  // Now we will calculate impulses required to fix collisions.
768  // All joints should be taken into account, but since we are
769  // calculating impulses we should "froze" the jacobian i.e.
770  // ignore it derivative
771  scatterVariables(_variables.data(), _errorsCalculation ? _variances.data() : NULL);
772 
773  // check and count contacts before the sparse matrix assembly
774  int contactsCount = 0;
775  int status = _collisionSolver->checkContacts(_bodies, true, &contactsCount);
776  if (contactsCount!=_constraintsInfo.contactsCount)
777  {
778  _constraintsInfo.setDimension(_constraintsInfo.variablesCount,
779  _constraintsInfo.constraintsCount,
780  contactsCount);
781  }
782 
783  _tempArray.setZero();
784  ::new (&_constraintsInfo.position) MappedVector(_variables.data(), _variablesCount);
785  ::new (&_constraintsInfo.velocity) MappedVector(_variables.data()+_variablesCount, _variablesCount);
786  ::new (&_constraintsInfo.acceleration) MappedVector(_tempArray.data(), _variablesCount);
787 
788  // start sparse matrix assembly
789  gatherJointsInfo(&_constraintsInfo);
790  _constraintsInfo.jacobianDerivative.setZero();
791 
792  if(status >= CollisionSolver::InternalError) { ret = status; goto out; }
793 
794  _collisionSolver->getContactsInfo(_constraintsInfo, true);
795  // end sparse matrix assembly
796 
797  if(_constraintsInfo.collisionFlag) {
798  ret = _constraintSolver->solve(&_constraintsInfo);
799  if(ret != Solver::OK) goto out;
800 
801  // XXX: variances
802  _constraintsInfo.velocity += _constraintsInfo.inverseMass.asDiagonal() * _constraintsInfo.force;
803  }
804  } else goto out;
805 
806  } while(_time + stepSize/100 <= collisionEndTime); // XXX
807  } else if(ret != Solver::OK) goto out;
808  }
809 
810 out:
811  scatterVariables(_variables.data(), _errorsCalculation ? _variances.data() : NULL);
812  return ret;
813 }
814 
815 inline int World::solverFunction(double t, const double* y,
816  const double* yvar, double* f, double* fvar)
817 {
818  if(_evolveAbort) return Solver::Aborted;
819 
820  _time = t;
821  scatterVariables(y, yvar); // this will reset force
822 
823  // 1. Forces
824  bool calcVariances = (fvar != NULL);
825  const ForceList::const_iterator f_end = _forces.end();
826  for(ForceList::iterator force = _forces.begin(); force != f_end; ++force) {
827  (*force)->calcForce(calcVariances);
828  }
829 
830  std::memcpy(f, y+_variablesCount, _variablesCount*sizeof(*f));
831  if(fvar) std::memcpy(fvar, y+_variablesCount, _variablesCount*sizeof(*fvar));
832  gatherAccelerations(f+_variablesCount, fvar ? fvar+_variablesCount : NULL);
833 
834  if (_constraintSolver)
835  {
836  // setup...
837 
838  // check contacts
839  int state = 0;
840  if(_collisionSolver) {
841  int contactsCount = 0;
842  state = _collisionSolver->checkContacts(_bodies, false, &contactsCount);
843 
844  if (contactsCount!=_constraintsInfo.contactsCount)
845  {
846  _constraintsInfo.setDimension(_constraintsInfo.variablesCount,
847  _constraintsInfo.constraintsCount,
848  contactsCount);
849  }
850  }
851 
852  if(_variablesCount>0)
853  {
854  ::new (&_constraintsInfo.position) MappedVector(y, _variablesCount);
855  ::new (&_constraintsInfo.velocity) MappedVector(y+_variablesCount, _variablesCount);
856  ::new (&_constraintsInfo.acceleration) MappedVector(f+_variablesCount, _variablesCount);
857  }
858 
859  // end sparse matrix assembly
860 
861  // 2. Joints
862  gatherJointsInfo(&_constraintsInfo);
863 
864  // 3. Collisions (TODO: variances for collisions)
865  if(_collisionSolver) {
866  _collisionSolver->getContactsInfo(_constraintsInfo, false);
867  if(state == Contact::Intersected) {
868  if(_stopOnIntersection) return Solver::IntersectionDetected;
869  } else {
870  if(state == Contact::Colliding) {
871  if(_stopOnCollision) return Solver::CollisionDetected;
872  // XXX: We are not stopping on colliding contact
873  // and resolving them only at the end of timestep
874  // XXX: is it right solution ? Shouldn't we try to find
875  // contact point more exactly for example using binary search ?
876  //_collisionTime = t;
877  //_collisionTime = t;
878  //if(t < _collisionExpectedTime)
879  // return DantzigLCPCollisionSolver::CollisionDetected;
880  } else if(state >= CollisionSolver::InternalError) {
881  return state;
882  }
883  }
884  }
885  // end sparse matrix assembly
886 
887  // 4. Solve constraints
888  if(_constraintsInfo.constraintsCount + _constraintsInfo.contactsCount > 0) {
889 
890  int state = _constraintSolver->solve(&_constraintsInfo);
891  if(state != Solver::OK) return state;
892 
893  int offset = 0;
894  const BodyList::const_iterator b_end = _bodies.end();
895  for(BodyList::iterator body = _bodies.begin(); body != b_end; ++body) {
896  (*body)->addForce(&_constraintsInfo.force[offset], NULL);
897  (*body)->getAccelerations(f+_variablesCount+offset, NULL);
898  offset += (*body)->variablesCount();
899  }
900  }
901  }
902 
903  return 0;
904 }
905 
906 int World::solverFunction(double t, const double* y,
907  const double* yvar, double* f, double* fvar, void* params)
908 {
909  return static_cast<World*>(params)->solverFunction(t, y, yvar, f, fvar);
910 }
911 
912 } // namespace StepCore
913 
StepCore::ConstraintsInfo::jacobianDerivative
DynSparseRowMatrix jacobianDerivative
Time-derivative of constraintsJacobian.
Definition: world.h:226
StepCore::World::removeCollisionSolver
CollisionSolver * removeCollisionSolver()
Get current CollisionSolver and remove it from world.
Definition: world.cc:583
StepCore::World::constraintSolver
ConstraintSolver * constraintSolver() const
Get current ConstraintSolver.
Definition: world.h:448
StepCore::World::ItemGroup
friend class ItemGroup
Definition: world.h:470
StepCore::Item::deleteObjectErrors
void deleteObjectErrors()
Delete objectErrors.
Definition: world.h:106
StepCore::ItemGroup::item
Item * item(const QString &name) const
Get any descendant item by its name.
Definition: world.cc:191
StepCore::World::object
Object * object(const QString &name)
Add new item to the world.
Definition: world.cc:549
StepCore::ConstraintsInfo::value
VectorXd value
Current constarints values (amount of brokenness)
Definition: world.h:223
StepCore::ConstraintsInfo::acceleration
MappedVector acceleration
Accelerations of the bodies before applying constraints.
Definition: world.h:231
StepCore::Solver::doEvolve
virtual int doEvolve(double *t, double t1, VectorXd *y, VectorXd *yvar)=0
Integrate.
STEPCORE_ASSERT_NOABORT
#define STEPCORE_ASSERT_NOABORT(expr)
Definition: util.h:58
StepCore::ConstraintSolver::solve
virtual int solve(ConstraintsInfo *info)=0
StepCore::World::removeConstraintSolver
ConstraintSolver * removeConstraintSolver()
Get current ConstraintSolver and remove it from world.
Definition: world.cc:596
StepCore::ItemGroup::worldItemRemoved
void worldItemRemoved(Item *item)
Recursively call worldItemRemoved for all children objects.
Definition: world.cc:87
StepCore::MetaObject::propertyCount
int propertyCount() const
Returns property count.
Definition: object.h:225
StepCore::ConstraintsInfo::contactsCount
int contactsCount
Number of additional constrains equations due to contacts.
Definition: world.h:220
StepCore::Item::operator=
Item & operator=(const Item &item)
Assignment operator (copies objectErrors if necessary)
StepCore::Object
Root of the StepCore classes hierarchy.
Definition: object.h:57
StepCore::ConstraintsInfo::variablesCount
int variablesCount
Number of dynamic variables.
Definition: world.h:218
StepCore::ItemGroup::~ItemGroup
~ItemGroup()
Destroys the group and all its subitems.
Definition: world.cc:132
StepCore::Item::setGroup
virtual void setGroup(ItemGroup *group)
Set/change pointer to ItemGroup in which this object lives.
Definition: world.h:94
StepCore::ConstraintsInfo::velocity
MappedVector velocity
Velocities of the bodies.
Definition: world.h:230
StepCore::MetaProperty::readVariant
QVariant readVariant(const Object *obj) const
Read property as QVariant.
Definition: object.h:131
StepCore::CollisionSolver::InternalError
Definition: collisionsolver.h:133
StepCore::Solver
Generic Solver interface.
Definition: solver.h:70
StepCore::ItemGroup::clear
void clear()
Deletes all items.
Definition: world.cc:116
StepCore::ItemGroup::childItem
Item * childItem(int index) const
Get direct child item by its index.
Definition: world.h:353
StepCore::STEPCORE_SUPER_CLASS
STEPCORE_SUPER_CLASS(CollisionSolver)
StepCore::Contact::Intersected
Bodies are interpenetrating.
Definition: collisionsolver.h:53
StepCore::World::World
World()
Constructs empty World.
Definition: world.cc:259
StepCore::Solver::OK
Definition: solver.h:142
StepCore::MetaProperty::writeVariant
bool writeVariant(Object *obj, const QVariant &v) const
Write property as QVariant.
Definition: object.h:133
StepCore::ConstraintsInfo::forceMin
VectorXd forceMin
Constraints force lower limit.
Definition: world.h:233
StepCore::ConstraintsInfo::setDimension
void setDimension(int newVariablesCount, int newConstraintsCount, int newContactsCount=0)
Set variablesCount, constraintsCount and reset contactsCount, resize all arrays appropriately.
Definition: world.cc:216
collisionsolver.h
CollisionSolver interface.
StepCore::ItemGroup::removeItem
virtual void removeItem(Item *item)
Remove item from the group (you should delete item youself)
Definition: world.cc:104
StepCore::ConstraintsInfo::constraintsCount
int constraintsCount
Number of constraints equations.
Definition: world.h:219
StepCore::CollisionSolver::getContactsInfo
virtual void getContactsInfo(ConstraintsInfo &info, bool collisions=false)=0
Fill the constraint info structure with the contacts computed by checkContacts()
StepCore::World::doEvolve
int doEvolve(double delta)
Integrate.
Definition: world.cc:699
StepCore::Item::world
World * world() const
Get pointer to World in which this object lives.
Definition: world.h:91
world.h
Item, Body, Force and Tool interfaces, World class.
StepCore::ItemGroup::addItem
virtual void addItem(Item *item)
Add new item to the group.
Definition: world.cc:94
StepCore::ConstraintsInfo::jacobian
DynSparseRowMatrix jacobian
Position-derivative of constraints values.
Definition: world.h:225
StepCore::QT_TRANSLATE_NOOP
QT_TRANSLATE_NOOP("ObjectClass","GJKCollisionSolver")
StepCore::MetaObject::property
const MetaProperty * property(int n) const
Returns property by index.
Definition: object.h:227
StepCore::Item::group
ItemGroup * group() const
Get pointer to ItemGroup in which this object lives.
Definition: world.h:97
StepCore::Contact::Colliding
Bodies are collising.
Definition: collisionsolver.h:52
StepCore::MappedVector
Eigen::Map< Eigen::VectorXd > MappedVector
Definition: types.h:39
StepCore::Item::setColor
void setColor(Color color)
Set item color (for use in GUI)
Definition: world.h:112
StepCore::ConstraintsInfo::forceMax
VectorXd forceMax
Constraints force upper limit.
Definition: world.h:234
StepCore::Solver::IntersectionDetected
Definition: solver.h:146
StepCore::World::~World
~World()
Destroys World and all objects which belongs to it.
Definition: world.cc:277
StepCore::CollisionSolver::bodyRemoved
virtual void bodyRemoved(BodyList &, Body *)
Definition: collisionsolver.h:129
StepCore::World::solver
Solver * solver() const
Get current Solver.
Definition: world.h:434
constraintsolver.h
ConstraintSolver interface.
StepCore::World::setSolver
void setSolver(Solver *solver)
Set new Solver (and delete the old one)
Definition: world.cc:559
StepCore::Solver::CollisionDetected
Definition: solver.h:145
StepCore::Solver::setParams
virtual void setParams(void *params)
Set callback function params.
Definition: solver.h:104
StepCore::Item
The root class for any world items (bodies and forces)
Definition: world.h:69
StepCore::ItemGroup::childItemIndex
int childItemIndex(const Item *item) const
Finds direct child item in items()
Definition: world.cc:176
StepCore::MetaObject::ABSTRACT
Class is abstract.
Definition: object.h:180
StepCore::ConstraintsInfo::derivative
VectorXd derivative
Time-derivative of constraints values.
Definition: world.h:224
StepCore::timeScale
timeScale
Definition: world.cc:43
StepCore::Item::createObjectErrors
virtual ObjectErrors * createObjectErrors()
Definition: world.h:124
StepCore::ObjectErrors
Base class for all errors objects.
Definition: world.h:49
StepCore::Object::name
const QString & name() const
Returns name of the object.
Definition: object.h:66
StepCore::Solver::Aborted
Definition: solver.h:147
StepCore::Object::Object
Object(const QString &name=QString())
Definition: object.h:62
StepCore::QT_TR_NOOP
QT_TR_NOOP("Errors class for CoulombForce")
StepCore::STEPCORE_UNITS_1
STEPCORE_UNITS_1
Definition: world.cc:43
StepCore::STEPCORE_PROPERTY_RW
STEPCORE_PROPERTY_RW(double, depth, QT_TRANSLATE_NOOP("PropertyName","depth"), QT_TRANSLATE_NOOP("Units","J"), QT_TR_NOOP("Potential depth"), depth, setDepth) STEPCORE_PROPERTY_RW(double
StepCore::ItemGroup
Groups several items together.
Definition: world.h:309
StepCore::CollisionSolver
Collision solver interface.
Definition: collisionsolver.h:85
StepCore::MetaProperty::userTypeId
int userTypeId() const
Returns property userType (see QMetaProperty)
Definition: object.h:129
solver.h
Solver interface.
StepCore::Solver::setFunction
virtual void setFunction(Function function)
Set callback function.
Definition: solver.h:99
StepCore::ItemList
std::vector< Item * > ItemList
List of pointers to Item.
Definition: world.h:298
STEPCORE_UNITS_NULL
#define STEPCORE_UNITS_NULL
Definition: object.h:365
StepCore::CollisionSolver::bodyAdded
virtual void bodyAdded(BodyList &, Body *)
Definition: collisionsolver.h:128
StepCore::World::collisionSolver
CollisionSolver * collisionSolver() const
Get current CollisionSolver.
Definition: world.h:441
StepCore::ItemGroup::setWorld
void setWorld(World *world)
Recursively call setWorld for all children objects.
Definition: world.cc:79
StepCore::STEPCORE_PROPERTY_RW_D
STEPCORE_PROPERTY_RW_D(StepCore::Vector2d, positionVariance, QT_TRANSLATE_NOOP("PropertyName","positionVariance"), QT_TRANSLATE_NOOP("Units","m"), QT_TR_NOOP("position variance"), positionVariance, setPositionVariance) STEPCORE_PROPERTY_RW_D(double
StepCore::World::setCollisionSolver
void setCollisionSolver(CollisionSolver *collisionSolver)
Set new CollisionSolver (and delete the old one)
Definition: world.cc:577
StepCore::World::operator=
World & operator=(const World &world)
Assignment operator (deep copy)
Definition: world.cc:323
StepCore::World::clear
void clear()
Clear world (removes all items, solver and resets time)
Definition: world.cc:282
StepCore::Item::objectErrors
ObjectErrors * objectErrors()
Get existing ObjectErrors or try to create it.
Definition: world.cc:67
StepCore::CollisionSolver::checkContacts
virtual int checkContacts(BodyList &bodies, bool collisions=false, int *count=NULL)=0
Check (and update) state of the contact.
StepCore::Object::setName
void setName(const QString &name)
Set name of the object.
Definition: object.h:68
StepCore::Solver::stepSize
double stepSize() const
Get step size.
Definition: solver.h:107
StepCore::Solver::doCalcFn
virtual int doCalcFn(double *t, const VectorXd *y, const VectorXd *yvar=0, VectorXd *f=0, VectorXd *fvar=0)=0
Calculate function value.
StepCore::ConstraintsInfo::inverseMass
VectorXd inverseMass
Diagonal coefficients of the inverse mass matrix of the system.
Definition: world.h:227
StepCore::ItemGroup::items
const ItemList & items() const
Get list of all direct child items in the ItemGroup.
Definition: world.h:326
StepCore::MetaObject
Meta-information about class.
Definition: object.h:176
StepCore::Item::setWorld
virtual void setWorld(World *world)
Set/change pointer to World in which this object lives.
Definition: world.h:88
StepCore::STEPCORE_META_OBJECT
STEPCORE_META_OBJECT(CollisionSolver, QT_TRANSLATE_NOOP("ObjectClass","CollisionSolver"),"CollisionSolver", MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object), STEPCORE_PROPERTY_RW(double, toleranceAbs, QT_TRANSLATE_NOOP("PropertyName","toleranceAbs"), STEPCORE_UNITS_1, QT_TR_NOOP("Allowed absolute tolerance"), toleranceAbs, setToleranceAbs) STEPCORE_PROPERTY_R_D(double, localError, QT_TRANSLATE_NOOP("PropertyName","localError"), STEPCORE_UNITS_1, QT_TR_NOOP("Maximal local error during last step"), localError)) STEPCORE_META_OBJECT(GJKCollisionSolver
StepCore::Solver::setDimension
virtual void setDimension(int dimension)
Set ODE dimension.
Definition: solver.h:94
StepCore::MetaProperty
Meta-information about property.
Definition: object.h:77
StepCore::ConstraintsInfo::position
MappedVector position
Positions of the bodies.
Definition: world.h:229
StepCore::World::removeSolver
Solver * removeSolver()
Get current Solver and remove it from world.
Definition: world.cc:570
StepCore::ConstraintsInfo::force
VectorXd force
Resulting constraints force.
Definition: world.h:236
StepCore::ConstraintSolver
Constraint solver interface.
Definition: constraintsolver.h:40
StepCore::ItemGroup::operator=
ItemGroup & operator=(const ItemGroup &group)
Assignment operator (deep copy)
Definition: world.cc:137
StepCore::ConstraintsInfo::clear
void clear()
Clear the structure.
Definition: world.cc:242
StepCore::World
Contains multiple Item, Solver and general properties such as time.
Definition: world.h:372
StepCore::Color
Definition: types.h:42
StepCore::World::setConstraintSolver
void setConstraintSolver(ConstraintSolver *constraintSolver)
Set new ConstraintSolver (and delete the old one)
Definition: world.cc:590
StepCore::ConstraintsInfo::collisionFlag
bool collisionFlag
True if there is a collision to be resolved.
Definition: world.h:238
StepCore::ItemGroup::ItemGroup
ItemGroup(const QString &name=QString())
Constructs empty group.
Definition: world.h:315
StepCore::CollisionSolver::resetCaches
virtual void resetCaches()
Reset internal caches of collision information.
Definition: collisionsolver.h:126
StepCore::World::time
double time() const
Get current time.
Definition: world.h:393
StepCore::World::doCalcFn
int doCalcFn()
Calculate all forces.
Definition: world.cc:685
StepCore::ItemGroup::allItems
ItemList allItems() const
Get list of all items in the ItemGroup.
Definition: world.h:331
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:43:06 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

step/stepcore

Skip menu "step/stepcore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal