Esempio n. 1
0
void ModelTests::modelTreeTests(bool verbose) {
    int testsTaken = 0;
    int testsPassed = 0;
    int testsFailed = 0;

    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
    qDebug() << "ModelTests::modelTreeTests()";

    // Tree, id, and model properties used in many tests below...
    ModelTree tree;
    uint32_t id = 1;
    ModelItemID modelID(id);
    modelID.isKnownID = false; // this is a temporary workaround to allow local tree models to be added with known IDs
    ModelItemProperties properties;
    float oneMeter = 1.0f;
    float halfMeter = oneMeter / 2.0f;
    float halfOfDomain = TREE_SCALE * 0.5f;
    glm::vec3 positionNearOriginInMeters(oneMeter, oneMeter, oneMeter); // when using properties, these are in meter not tree units
    glm::vec3 positionAtCenterInMeters(halfOfDomain, halfOfDomain, halfOfDomain);
    glm::vec3 positionNearOriginInTreeUnits = positionNearOriginInMeters / (float)TREE_SCALE;
    glm::vec3 positionAtCenterInTreeUnits = positionAtCenterInMeters / (float)TREE_SCALE;

    {
        testsTaken++;
        QString testName = "add model to tree and search";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        properties.setPosition(positionAtCenterInMeters);
        properties.setRadius(halfMeter);
        properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx");

        tree.addModel(modelID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const ModelItem* foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius);
        const ModelItem* foundModelByID = tree.findModelByID(id);
        
        if (verbose) {
            qDebug() << "foundModelByRadius=" << foundModelByRadius;
            qDebug() << "foundModelByID=" << foundModelByID;
        }

        bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    modelID.isKnownID = true; // this is a temporary workaround to allow local tree models to be added with known IDs

    {
        testsTaken++;
        QString testName = "change position of model in tree";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        glm::vec3 newPosition = positionNearOriginInMeters;

        properties.setPosition(newPosition);

        tree.updateModel(modelID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const ModelItem* foundModelByRadius = tree.findClosestModel(positionNearOriginInTreeUnits, targetRadius);
        const ModelItem* foundModelByID = tree.findModelByID(id);
        
        if (verbose) {
            qDebug() << "foundModelByRadius=" << foundModelByRadius;
            qDebug() << "foundModelByID=" << foundModelByID;
        }

        // NOTE: This test is currently expected to fail in the production code. There's a bug in ModelTree::updateModel()
        // that does not update the actual location of the model into the correct element when modified locally. So this
        // test will fail. There's a new optimized and correctly working version of updateModel() that fixes this problem.
        bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID);
        if (passed) {
            testsPassed++;
            qDebug() << "NOTE: Expected to FAIL - Test" << testsTaken <<":" << qPrintable(testName);
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
            qDebug() << "NOTE: Expected to FAIL - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    {
        testsTaken++;
        QString testName = "change position of model in tree back to center";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        glm::vec3 newPosition = positionAtCenterInMeters;

        properties.setPosition(newPosition);

        tree.updateModel(modelID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const ModelItem* foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius);
        const ModelItem* foundModelByID = tree.findModelByID(id);
        
        if (verbose) {
            qDebug() << "foundModelByRadius=" << foundModelByRadius;
            qDebug() << "foundModelByID=" << foundModelByID;
        }

        bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    {
        testsTaken++;
        QString testName = "Performance - findClosestModel() 1,000,000 times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const int TEST_ITERATIONS = 1000000;
        quint64 start = usecTimestampNow();
        const ModelItem* foundModelByRadius = NULL;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius);
        }
        quint64 end = usecTimestampNow();
        
        if (verbose) {
            qDebug() << "foundModelByRadius=" << foundModelByRadius;
        }

        bool passed = foundModelByRadius;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs";
    }

    {
        testsTaken++;
        QString testName = "Performance - findModelByID() 1,000,000 times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        const int TEST_ITERATIONS = 1000000;
        quint64 start = usecTimestampNow();
        const ModelItem* foundModelByID = NULL;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            foundModelByID = tree.findModelByID(id);
        }
        quint64 end = usecTimestampNow();
        
        if (verbose) {
            qDebug() << "foundModelByID=" << foundModelByID;
        }

        bool passed = foundModelByID;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs";
    }

    {
        testsTaken++;
        QString testName = "Performance - add model to tree 10,000 times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        const int TEST_ITERATIONS = 10000;
        quint64 start = usecTimestampNow();
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            uint32_t id = i + 2; // make sure it doesn't collide with previous model ids
            ModelItemID modelID(id);
            modelID.isKnownID = false; // this is a temporary workaround to allow local tree models to be added with known IDs

            float randomX = randFloatInRange(0.0f ,(float)TREE_SCALE);
            float randomY = randFloatInRange(0.0f ,(float)TREE_SCALE);
            float randomZ = randFloatInRange(0.0f ,(float)TREE_SCALE);
            glm::vec3 randomPositionInMeters(randomX,randomY,randomZ);

            properties.setPosition(randomPositionInMeters);
            properties.setRadius(halfMeter);
            properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx");

            tree.addModel(modelID, properties);
        }
        quint64 end = usecTimestampNow();
        
        bool passed = true;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs";
    }

    qDebug() << "   tests passed:" << testsPassed << "out of" << testsTaken;
    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
}
Esempio n. 2
0
void EntityTests::entityTreeTests(bool verbose) {

    bool extraVerbose = false;
    int testsTaken = 0;
    int testsPassed = 0;
    int testsFailed = 0;

    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
    qDebug() << "EntityTests::entityTreeTests()";

    // Tree, id, and entity properties used in many tests below...
    EntityTree tree;
    QUuid id = QUuid::createUuid();
    EntityItemID entityID(id);
    entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
    EntityItemProperties properties;
    float oneMeter = 1.0f;
    //float halfMeter = oneMeter / 2.0f;
    float halfOfDomain = TREE_SCALE * 0.5f;
    glm::vec3 positionNearOriginInMeters(oneMeter, oneMeter, oneMeter); // when using properties, these are in meter not tree units
    glm::vec3 positionAtCenterInMeters(halfOfDomain, halfOfDomain, halfOfDomain);
    glm::vec3 positionNearOriginInTreeUnits = positionNearOriginInMeters / (float)TREE_SCALE;
    glm::vec3 positionAtCenterInTreeUnits = positionAtCenterInMeters / (float)TREE_SCALE;

    {
        testsTaken++;
        QString testName = "add entity to tree and search";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        properties.setPosition(positionAtCenterInMeters);
        // TODO: Fix these unit tests.
        //properties.setRadius(halfMeter);
        //properties.setModelURL("http://s3.amazonaws.com/hifi-public/ozan/theater.fbx");

        tree.addEntity(entityID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const EntityItem* foundEntityByRadius = tree.findClosestEntity(positionAtCenterInTreeUnits, targetRadius);
        const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
        EntityTreeElement* containingElement = tree.getContainingElement(entityID);
        AACube elementCube = containingElement ? containingElement->getAACube() : AACube();
        
        if (verbose) {
            qDebug() << "foundEntityByRadius=" << foundEntityByRadius;
            qDebug() << "foundEntityByID=" << foundEntityByID;
            qDebug() << "containingElement=" << containingElement;
            qDebug() << "containingElement.box=" 
                << elementCube.getCorner().x * TREE_SCALE << "," 
                << elementCube.getCorner().y * TREE_SCALE << ","
                << elementCube.getCorner().z * TREE_SCALE << ":" 
                << elementCube.getScale() * TREE_SCALE;
            qDebug() << "elementCube.getScale()=" << elementCube.getScale();
            //containingElement->printDebugDetails("containingElement");
        }

        bool passed = foundEntityByRadius && foundEntityByID && (foundEntityByRadius == foundEntityByID);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs

    {
        testsTaken++;
        QString testName = "change position of entity in tree";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        glm::vec3 newPosition = positionNearOriginInMeters;

        properties.setPosition(newPosition);

        tree.updateEntity(entityID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const EntityItem* foundEntityByRadius = tree.findClosestEntity(positionNearOriginInTreeUnits, targetRadius);
        const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
        EntityTreeElement* containingElement = tree.getContainingElement(entityID);
        AACube elementCube = containingElement ? containingElement->getAACube() : AACube();
        
        if (verbose) {
            qDebug() << "foundEntityByRadius=" << foundEntityByRadius;
            qDebug() << "foundEntityByID=" << foundEntityByID;
            qDebug() << "containingElement=" << containingElement;
            qDebug() << "containingElement.box=" 
                << elementCube.getCorner().x * TREE_SCALE << "," 
                << elementCube.getCorner().y * TREE_SCALE << ","
                << elementCube.getCorner().z * TREE_SCALE << ":" 
                << elementCube.getScale() * TREE_SCALE;
            //containingElement->printDebugDetails("containingElement");
        }

        bool passed = foundEntityByRadius && foundEntityByID && (foundEntityByRadius == foundEntityByID);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    {
        testsTaken++;
        QString testName = "change position of entity in tree back to center";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }
        
        glm::vec3 newPosition = positionAtCenterInMeters;

        properties.setPosition(newPosition);

        tree.updateEntity(entityID, properties);
        
        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        const EntityItem* foundEntityByRadius = tree.findClosestEntity(positionAtCenterInTreeUnits, targetRadius);
        const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
        EntityTreeElement* containingElement = tree.getContainingElement(entityID);
        AACube elementCube = containingElement ? containingElement->getAACube() : AACube();
        
        if (verbose) {
            qDebug() << "foundEntityByRadius=" << foundEntityByRadius;
            qDebug() << "foundEntityByID=" << foundEntityByID;
            qDebug() << "containingElement=" << containingElement;
            qDebug() << "containingElement.box=" 
                << elementCube.getCorner().x * TREE_SCALE << "," 
                << elementCube.getCorner().y * TREE_SCALE << ","
                << elementCube.getCorner().z * TREE_SCALE << ":" 
                << elementCube.getScale() * TREE_SCALE;
            //containingElement->printDebugDetails("containingElement");
        }

        bool passed = foundEntityByRadius && foundEntityByID && (foundEntityByRadius == foundEntityByID);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
    }

    {
        testsTaken++;
        const int TEST_ITERATIONS = 1000;
        QString testName = "Performance - findClosestEntity() "+ QString::number(TEST_ITERATIONS) + " times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
        quint64 start = usecTimestampNow();
        const EntityItem* foundEntityByRadius = NULL;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            foundEntityByRadius = tree.findClosestEntity(positionAtCenterInTreeUnits, targetRadius);
        }
        quint64 end = usecTimestampNow();
        
        if (verbose) {
            qDebug() << "foundEntityByRadius=" << foundEntityByRadius;
        }

        bool passed = foundEntityByRadius;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs";
    }

    {
        testsTaken++;
        const int TEST_ITERATIONS = 1000;
        QString testName = "Performance - findEntityByID() "+ QString::number(TEST_ITERATIONS) + " times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        quint64 start = usecTimestampNow();
        const EntityItem* foundEntityByID = NULL;
        for (int i = 0; i < TEST_ITERATIONS; i++) {
            // TODO: does this need to be updated??
            foundEntityByID = tree.findEntityByEntityItemID(entityID);
        }
        quint64 end = usecTimestampNow();
        
        if (verbose) {
            qDebug() << "foundEntityByID=" << foundEntityByID;
        }

        bool passed = foundEntityByID;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs";
    }

    {
        // seed the random number generator so that our tests are reproducible
        srand(0xFEEDBEEF);
    
        testsTaken++;
        const int TEST_ITERATIONS = 1000;
        QString testName = "Performance - add entity to tree " + QString::number(TEST_ITERATIONS) + " times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        int iterationsPassed = 0;
        quint64 totalElapsedAdd = 0;
        quint64 totalElapsedFind = 0;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
            EntityItemID entityID(id);
            entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs

            float randomX = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
            float randomY = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
            float randomZ = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
            glm::vec3 randomPositionInMeters(randomX,randomY,randomZ);
            glm::vec3 randomPositionInTreeUnits = randomPositionInMeters / (float)TREE_SCALE;

            properties.setPosition(randomPositionInMeters);
            
            // TODO: fix these unit tests
            //properties.setRadius(halfMeter);
            //properties.setModelURL("http://s3.amazonaws.com/hifi-public/ozan/theater.fbx");

            if (extraVerbose) {
                qDebug() << "iteration:" << i
                      << "ading entity at x/y/z=" << randomX << "," << randomY << "," << randomZ;
                qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startAdd = usecTimestampNow();
            tree.addEntity(entityID, properties);
            quint64 endAdd = usecTimestampNow();
            totalElapsedAdd += (endAdd - startAdd);

            if (extraVerbose) {
                qDebug() << "after:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startFind = usecTimestampNow();
            float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units
            const EntityItem* foundEntityByRadius = tree.findClosestEntity(randomPositionInTreeUnits, targetRadius);
            const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
            quint64 endFind = usecTimestampNow();
            totalElapsedFind += (endFind - startFind);

            EntityTreeElement* containingElement = tree.getContainingElement(entityID);
            AACube elementCube = containingElement ? containingElement->getAACube() : AACube();
            
            bool elementIsBestFit = containingElement->bestFitEntityBounds(foundEntityByID);
            
            if (extraVerbose) {
                qDebug() << "foundEntityByRadius=" << foundEntityByRadius;
                qDebug() << "foundEntityByID=" << foundEntityByID;
                qDebug() << "containingElement=" << containingElement;
                qDebug() << "containingElement.box=" 
                    << elementCube.getCorner().x * TREE_SCALE << "," 
                    << elementCube.getCorner().y * TREE_SCALE << ","
                    << elementCube.getCorner().z * TREE_SCALE << ":" 
                    << elementCube.getScale() * TREE_SCALE;
                qDebug() << "elementCube.getScale()=" << elementCube.getScale();
                //containingElement->printDebugDetails("containingElement");
                qDebug() << "elementIsBestFit=" << elementIsBestFit;
            }
            
            // Every 1000th test, show the size of the tree...
            if (extraVerbose && (i % 1000 == 0)) {
                qDebug() << "after test:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            bool passed = foundEntityByRadius && foundEntityByID && (foundEntityByRadius == foundEntityByID) && elementIsBestFit;
            if (passed) {
              iterationsPassed++;
            } else {
                if (extraVerbose) {
                    qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName) << "iteration:" << i
                          << "foundEntityByRadius=" << foundEntityByRadius << "foundEntityByID=" << foundEntityByID
                          << "x/y/z=" << randomX << "," << randomY << "," << randomZ
                          << "elementIsBestFit=" << elementIsBestFit;
                }
            }
        }

        if (extraVerbose) {
            qDebug() << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
        }
        
        bool passed = iterationsPassed == TEST_ITERATIONS;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecsAdd = (float)(totalElapsedAdd) / USECS_PER_MSECS;
        float elapsedInMSecsFind = (float)(totalElapsedFind) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) 
                        << "elapsed Add=" << elapsedInMSecsAdd << "msecs"
                        << "elapsed Find=" << elapsedInMSecsFind << "msecs";
    }

    {
        testsTaken++;
        const int TEST_ITERATIONS = 1000;
        QString testName = "Performance - delete entity from tree " + QString::number(TEST_ITERATIONS) + " times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        int iterationsPassed = 0;
        quint64 totalElapsedDelete = 0;
        quint64 totalElapsedFind = 0;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        
            QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
            EntityItemID entityID(id);
            entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs

            if (extraVerbose) {
                qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startDelete = usecTimestampNow();
            tree.deleteEntity(entityID);
            quint64 endDelete = usecTimestampNow();
            totalElapsedDelete += (endDelete - startDelete);

            if (extraVerbose) {
                qDebug() << "after:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startFind = usecTimestampNow();
            const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
            quint64 endFind = usecTimestampNow();
            totalElapsedFind += (endFind - startFind);

            EntityTreeElement* containingElement = tree.getContainingElement(entityID);
            
            if (extraVerbose) {
                qDebug() << "foundEntityByID=" << foundEntityByID;
                qDebug() << "containingElement=" << containingElement;
            }
            
            // Every 1000th test, show the size of the tree...
            if (extraVerbose && (i % 1000 == 0)) {
                qDebug() << "after test:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            bool passed = foundEntityByID == NULL && containingElement == NULL;
            if (passed) {
              iterationsPassed++;
            } else {
                if (extraVerbose) {
                    qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName) << "iteration:" << i
                          << "foundEntityByID=" << foundEntityByID
                          << "containingElement=" << containingElement;
                }
            }
        }

        if (extraVerbose) {
            qDebug() << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
        }
        
        bool passed = iterationsPassed == TEST_ITERATIONS;
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecsDelete = (float)(totalElapsedDelete) / USECS_PER_MSECS;
        float elapsedInMSecsFind = (float)(totalElapsedFind) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) 
                        << "elapsed Delete=" << elapsedInMSecsDelete << "msecs"
                        << "elapsed Find=" << elapsedInMSecsFind << "msecs";
    }


    {
        testsTaken++;
        const int TEST_ITERATIONS = 100;
        const int ENTITIES_PER_ITERATION = 10;
        QString testName = "Performance - delete " + QString::number(ENTITIES_PER_ITERATION) 
                            + " entities from tree " + QString::number(TEST_ITERATIONS) + " times";
        if (verbose) {
            qDebug() << "Test" << testsTaken <<":" << qPrintable(testName);
        }

        int iterationsPassed = 0;
        quint64 totalElapsedDelete = 0;
        quint64 totalElapsedFind = 0;
        for (int i = 0; i < TEST_ITERATIONS; i++) {        

            QSet<EntityItemID> entitiesToDelete;
            for (int j = 0; j < ENTITIES_PER_ITERATION; j++) {        
                //uint32_t id = 2 + (i * ENTITIES_PER_ITERATION) + j; // These are the entities we added above
                QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
                EntityItemID entityID(id);
                entitiesToDelete << entityID;
            }

            if (extraVerbose) {
                qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startDelete = usecTimestampNow();
            tree.deleteEntities(entitiesToDelete);
            quint64 endDelete = usecTimestampNow();
            totalElapsedDelete += (endDelete - startDelete);

            if (extraVerbose) {
                qDebug() << "after:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
            }

            quint64 startFind = usecTimestampNow();
            for (int j = 0; j < ENTITIES_PER_ITERATION; j++) {        
                //uint32_t id = 2 + (i * ENTITIES_PER_ITERATION) + j; // These are the entities we added above
                QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
                EntityItemID entityID(id);
                const EntityItem* foundEntityByID = tree.findEntityByEntityItemID(entityID);
                EntityTreeElement* containingElement = tree.getContainingElement(entityID);

                if (extraVerbose) {
                    qDebug() << "foundEntityByID=" << foundEntityByID;
                    qDebug() << "containingElement=" << containingElement;
                }
                bool passed = foundEntityByID == NULL && containingElement == NULL;
                if (passed) {
                  iterationsPassed++;
                } else {
                    if (extraVerbose) {
                        qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName) << "iteration:" << i
                              << "foundEntityByID=" << foundEntityByID
                              << "containingElement=" << containingElement;
                    }
                }

            }

            quint64 endFind = usecTimestampNow();
            totalElapsedFind += (endFind - startFind);
        }

        if (extraVerbose) {
            qDebug() << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
        }
        
        bool passed = iterationsPassed == (TEST_ITERATIONS * ENTITIES_PER_ITERATION);
        if (passed) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName);
        }
        float USECS_PER_MSECS = 1000.0f;
        float elapsedInMSecsDelete = (float)(totalElapsedDelete) / USECS_PER_MSECS;
        float elapsedInMSecsFind = (float)(totalElapsedFind) / USECS_PER_MSECS;
        qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) 
                        << "elapsed Delete=" << elapsedInMSecsDelete << "msecs"
                        << "elapsed Find=" << elapsedInMSecsFind << "msecs";
    }

    qDebug() << "   tests passed:" << testsPassed << "out of" << testsTaken;
    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
}