int main() { WorldParameters parameters; parameters.setWorldMinMax(Vector3(-1000, -1000, -1000), Vector3(50000, 50000, 50000)); World world(parameters); std::vector<Proxy*> boxes; int countPerDimension = 10; int proxyCount = countPerDimension * countPerDimension * countPerDimension; Vector3 boxSize = Vector3(10.0, 10.0, 10.0); Vector3 boxOffset = Vector3(10.0, 10.0, 10.0); // distance between two boxes boxes = createManyRigidBoxes(&world, boxSize, proxyCount); int box = 0; Vector3 dist = boxSize + boxOffset; for (int x = 0; x < countPerDimension; x++) { for (int y = 0; y < countPerDimension; y++) { for (int z = 0; z < countPerDimension; z++) { Proxy* p = boxes.at(box); p->translate(dist.getX() * x, dist.getY() * y, dist.getZ() * z); box++; } } } world.prepareSimulation(); std::vector<Vector3> translationPerStep; translationPerStep.reserve(proxyCount); /* * 0 = constant translation for all proxies * 1 = disable movement */ int translationMode = 0; switch (translationMode) { case 0: // constant translation { Vector3 translation = Vector3(1.0, 1.0, 1.0); for (int i = 0; i < proxyCount; i++) { translationPerStep.push_back(translation); } break; } case 1: break; default: error() << "unknown translationMode " << translationMode; return 1; } /* * >= 0: do that many iterations * < 0: do infinite iterations */ int maxIterations = 20; bool useThreads = true; debug() << "starting collision detection with " << proxyCount << " proxies"; int reverseMovementCounter = 0; for (int iteration = 0; maxIterations < 0 || iteration < maxIterations; iteration++) { // move all proxies by one step for (int i = 0; i < proxyCount; i++) { boxes[i]->translate(translationPerStep[i]); } reverseMovementCounter++; if (reverseMovementCounter > 100) { reverseMovementCounter = 0; for (std::vector<Vector3>::iterator it = translationPerStep.begin(); it != translationPerStep.end(); ++it) { (*it) = (*it) * -1; } } unsigned int flags = World::COLLISIONFLAG_SKIP_MIDDLE_PHASE; if (useThreads) { flags |= World::COLLISIONFLAG_USE_THREADS; } world.calculateAllCollisions(flags); if (world.getDebugLog()) { // world.getDebugLog()->printSummary(); } } return 0; }
void WorldTest::simulationTestUncached() { World* world = new World(Vector3(200000, 200000, 200000)); world->setUseCollisionCaching(false); Vector3 boxDimensions(10, 10, 10); Proxy* box1 = world->createProxy(new Box(boxDimensions)); //Proxy* childBox = world->createProxy(new Box(boxDimensions)); //childBox->translate(5, 5, 5); //box->addChild(childBox); world->addProxy(box1); Proxy* box2 = world->createProxy(new Box(boxDimensions)); box2->translate(0, -20, 0); world->addProxy(box2); Proxy* box3 = world->createProxy(new Box(boxDimensions)); //always colliding with box2 box3->translate(5, -25, 0); world->addProxy(box3); Proxy* moveBox = world->createProxy(new Box(Vector3(10, 50, 10))); moveBox->translate(20, -25, 0); //starting in no-collision state world->addProxy(moveBox); //WorldCollisions coll; world->prepareSimulation(); //std::cout << "-----------Starting simulation test-----------"<<std::endl; //std::cout << "doing pre-move collisionCheck"<<std::endl; //test and ensure 1 BPC and rigid C WorldCollisions coll0 = world->calculateAllCollisions(); CPPUNIT_ASSERT_EQUAL(1, (int)coll0.getBroadPhaseCollisions()->getResults().size()); CPPUNIT_ASSERT_EQUAL(1, (int)coll0.getRigidBoundingVolumeCollisions().size()); //Step 1 -> move moveBox to collidy with box3 //std::cout <<std::endl<< "doing step 1 - move in to collide with box3"<<std::endl; moveBox->translate(-6, 0, 0); //ensure 2 BPC/RC WorldCollisions coll1 = world->calculateAllCollisions(); CPPUNIT_ASSERT_EQUAL(2, (int)coll1.getBroadPhaseCollisions()->getResults().size()); CPPUNIT_ASSERT_EQUAL(2, (int)coll1.getRigidBoundingVolumeCollisions().size()); //Step 2-> move to collide with all boxes //std::cout <<std::endl<<"doing step 2 - move further to collide with all"<<std::endl; moveBox->translate(-5, 0, 0); //ensure 4 collisions WorldCollisions coll2 = world->calculateAllCollisions(); CPPUNIT_ASSERT_EQUAL(4, (int)coll2.getBroadPhaseCollisions()->getResults().size()); CPPUNIT_ASSERT_EQUAL(4, (int)coll2.getRigidBoundingVolumeCollisions().size()); //Step 3-> move out again //std::cout << std::endl<<"doing step 3 - moving out"<<std::endl; moveBox->translate(11, 0, 0); //ensure 1 collisions WorldCollisions coll3 = world->calculateAllCollisions(); CPPUNIT_ASSERT_EQUAL(1, (int)coll3.getBroadPhaseCollisions()->getResults().size()); CPPUNIT_ASSERT_EQUAL(1, (int)coll3.getRigidBoundingVolumeCollisions().size()); //Step 4-> move in again //std::cout << std::endl<<"doing step 4 - moving back in"<<std::endl; moveBox->translate(-11, 0, 0); //ensure 4 collisions WorldCollisions coll4 = world->calculateAllCollisions(); CPPUNIT_ASSERT_EQUAL(4, (int)coll4.getBroadPhaseCollisions()->getResults().size()); CPPUNIT_ASSERT_EQUAL(4, (int)coll4.getRigidBoundingVolumeCollisions().size()); delete world; }
void UndoTest::testUndo() { // we maintain 2 World objects, a "undo" World and a "reference" world // // we will do some changes on both worlds and then do some changes on // the "undo" world only. after calling undo, both worlds should be // synced again. // // whenever we start tests, both worlds should be synced. World undoWorld; World referenceWorld; // add simple proxies and never move them // this tests in particular that a undoStep() call does not change // things that shouldnt change undoWorld.addProxy(undoWorld.createProxy(new Box(10, 10, 10))); referenceWorld.addProxy(referenceWorld.createProxy(new Box(10, 10, 10))); // add simple proxies, move them before adding, never move them // afterwards // this tests in particular that a undoStep() call does not change // things that shouldnt change Proxy* staticUndoProxy = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* staticRefereceProxy = referenceWorld.createProxy(new Box(10, 10, 10)); staticUndoProxy->translate(-10, 10, 5); staticRefereceProxy->translate(-10, 10, 5); undoWorld.addProxy(staticUndoProxy); referenceWorld.addProxy(staticRefereceProxy); // add simple proxies, but move them before adding Proxy* proxyUndoWorld = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* proxyReferenceWorld = referenceWorld.createProxy(new Box(10, 10, 10)); proxyUndoWorld->translate(-10, 10, 5); proxyReferenceWorld->translate(-10, 10, 5); undoWorld.addProxy(proxyUndoWorld); referenceWorld.addProxy(proxyReferenceWorld); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.startNextStep(); referenceWorld.startNextStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo simple translations proxyUndoWorld->translate(100, 100, 100); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo multiple translations proxyUndoWorld->translate(100, 100, 100); proxyUndoWorld->translate(100, 300, 200); proxyUndoWorld->translate(100, 400, 500); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo simple rotations proxyUndoWorld->rotate(45, 1, 0, 0); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo multiple simple rotations proxyUndoWorld->rotate(45, 1, 0, 0); proxyUndoWorld->rotate(15, 1, 0, 0); proxyUndoWorld->rotate(45, 0, 1, 0); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo translations and rotations proxyUndoWorld->translate(100, 100, 100); proxyUndoWorld->rotate(45, 1, 0, 0); proxyUndoWorld->translate(100, 1, 100); proxyUndoWorld->rotate(15, 1, 0, 0); proxyUndoWorld->translate(100, 20, 100); proxyUndoWorld->rotate(45, 0, 1, 0); proxyUndoWorld->translate(100, 100, 400); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo setTransformation() Matrix m; m.translate(100, 0, 0); proxyUndoWorld->setTransformation(m); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo multiple setTransformation() m = Matrix(); m.translate(100, 0, 0); proxyUndoWorld->setTransformation(m); m.translate(0, 50, 0); proxyUndoWorld->setTransformation(m); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo setProxyType() proxyUndoWorld->setProxyType(PROXYTYPE_DEFORMABLE); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // undo multiple setProxyType() proxyUndoWorld->setProxyType(PROXYTYPE_DEFORMABLE); proxyUndoWorld->setProxyType(PROXYTYPE_FIXED); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); //////////////////////////////////////////////////////////////// // build up a simple hierarchy with static + non-static children //////////////////////////////////////////////////////////////// Proxy* staticChildUndoWorld = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* staticChildReferenceWorld = referenceWorld.createProxy(new Box(10, 10, 10)); staticChildUndoWorld->translate(40, 10, 10); staticChildReferenceWorld->translate(40, 10, 10); proxyUndoWorld->addChild(staticChildUndoWorld); proxyReferenceWorld->addChild(staticChildReferenceWorld); Proxy* childUndoWorld = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* childReferenceWorld = referenceWorld.createProxy(new Box(10, 10, 10)); childUndoWorld->translate(0, 0, 10); childReferenceWorld->translate(0, 0, 10); childUndoWorld->rotate(100, 0, 0, 1); childReferenceWorld->rotate(100, 0, 0, 1); proxyUndoWorld->addChild(childUndoWorld); proxyReferenceWorld->addChild(childReferenceWorld); Proxy* staticGrandChildUndoWorld = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* staticGrandChildReferenceWorld = referenceWorld.createProxy(new Box(10, 10, 10)); staticGrandChildUndoWorld->translate(20, 10, 10); staticGrandChildReferenceWorld->translate(20, 10, 10); childUndoWorld->addChild(staticGrandChildUndoWorld); childReferenceWorld->addChild(staticGrandChildReferenceWorld); //////////////////////////////////// // build up a simple hierarchy (end) //////////////////////////////////// // sanity check CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // adding child proxies should not have any influence on undo, i.e. undo // should be a noop here. undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); Proxy* dummyUndoProxy = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* dummyReferenceProxy = referenceWorld.createProxy(new Box(10, 10, 10)); undoWorld.addProxy(dummyUndoProxy); referenceWorld.addProxy(dummyReferenceProxy); // another check that the addProxy() did not change anything CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); ////////////////////////////////////// // add grand-children to the hierarchy ////////////////////////////////////// Proxy* grandChildUndoWorld = undoWorld.createProxy(new Box(10, 10, 10)); Proxy* grandChildReferenceWorld = referenceWorld.createProxy(new Box(10, 10, 10)); grandChildUndoWorld->translate(0, 0, 100); grandChildReferenceWorld->translate(0, 0, 100); grandChildUndoWorld->rotate(100, 0, 0, 1); grandChildReferenceWorld->rotate(100, 0, 0, 1); childUndoWorld->addChild(grandChildUndoWorld); childReferenceWorld->addChild(grandChildReferenceWorld); //////////////////////////////////////////// // add grand-children to the hierarchy (end) //////////////////////////////////////////// // check that grand-children adding did not change anything CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check for undo on children childUndoWorld->translate(60, 0, 0); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check for undo on grand-children grandChildUndoWorld->translate(60, 0, 0); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check for undo on the whole hierarchy proxyUndoWorld->translate(5, 5, 5); childUndoWorld->rotate(54, 1, 0, 0); m = Matrix(); m.translate(10, 10, 10); m.rotate(44, 1, 0, 0); grandChildUndoWorld->setTransformation(m); grandChildUndoWorld->translate(60, 0, 0); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check that removeProxy() is NOT undone undoWorld.removeProxy(dummyUndoProxy); referenceWorld.removeProxy(dummyReferenceProxy); delete dummyUndoProxy; delete dummyReferenceProxy; CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); proxyUndoWorld->translate(10, 10, 10); proxyReferenceWorld->translate(10, 10, 10); // undo should cause the worlds NOT to be equal undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(false, checkWorldsAreEqual(&undoWorld, &referenceWorld)); proxyUndoWorld->translate(10, 10, 10); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check that that startNextStep() actually works as intended, i.e. we undo // the things _after_ the startNextStep(), not the ones before undoWorld.startNextStep(); // startNextStep() should not undo anything (except the moveflags) CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // startNextStep() should clear all possible "undo" values, i.e. this // should be a noop undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // things _after_ a startNextStep() should be undone again proxyUndoWorld->translate(10, 10, 10); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check that removing of grand-children does not change anything childUndoWorld->removeChild(grandChildUndoWorld); childReferenceWorld->removeChild(grandChildReferenceWorld); delete grandChildUndoWorld; delete grandChildReferenceWorld; CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // check that calls to startNextStep() after removeChild() still works undoWorld.startNextStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); undoWorld.undoStep(); CPPUNIT_ASSERT_EQUAL(true, checkWorldsAreEqual(&undoWorld, &referenceWorld)); // TODO: check that deformations are un-done? // open question: do we want to support un-doing of deformations? }