void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const AACube& newCube) {
    EntityTreeElementPointer oldContainingElement = entity->getElement();
    AABox newCubeClamped = newCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE);

    if (_wantDebug) {
        qCDebug(entities) << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
        qCDebug(entities) << "    newCube:" << newCube;
        qCDebug(entities) << "    newCubeClamped:" << newCubeClamped;
        if (oldContainingElement) {
            qCDebug(entities) << "    oldContainingElement:" << oldContainingElement->getAACube();
            qCDebug(entities) << "    oldContainingElement->bestFitBounds(newCubeClamped):" 
                            << oldContainingElement->bestFitBounds(newCubeClamped);
        } else {
            qCDebug(entities) << "    WARNING NO OLD CONTAINING ELEMENT for entity" << entity->getEntityItemID();
        }
    }

    if (!oldContainingElement) {
        return; // bail without adding.
    }

    // If the original containing element is the best fit for the requested newCube locations then
    // we don't actually need to add the entity for moving and we can short circuit all this work
    if (!oldContainingElement->bestFitBounds(newCubeClamped)) {
        // check our tree, to determine if this entity is known
        EntityToMoveDetails details;
        details.oldContainingElement = oldContainingElement;
        details.oldContainingElementCube = oldContainingElement->getAACube();
        details.entity = entity;
        details.oldFound = false;
        details.newFound = false;
        details.newCube = newCube;
        details.newCubeClamped = newCubeClamped;
        _entitiesToMove << details;
        _lookingCount++;

        if (_wantDebug) {
            qCDebug(entities) << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
            qCDebug(entities) << "    details.entity:" << details.entity->getEntityItemID();
            qCDebug(entities) << "    details.oldContainingElementCube:" << details.oldContainingElementCube;
            qCDebug(entities) << "    details.newCube:" << details.newCube;
            qCDebug(entities) << "    details.newCubeClamped:" << details.newCubeClamped;
            qCDebug(entities) << "    _lookingCount:" << _lookingCount;
            qCDebug(entities) << "--------------------------------------------------------------------------";
        }
    } else {
        if (_wantDebug) {
            qCDebug(entities) << "    oldContainingElement->bestFitBounds(newCubeClamped) IS BEST FIT... NOTHING TO DO";
        }
    }

    if (_wantDebug) {
        qCDebug(entities) << "--------------------------------------------------------------------------";
    }
}
Example #2
0
void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::VisibleElement& next,
        const DiffTraversal::View& view, const DiffTraversal::View& lastView) {
    if (_nextIndex == -1) {
        // root case is special
        ++_nextIndex;
        EntityTreeElementPointer element = _weakElement.lock();
        next.element = element;
        next.intersection = ViewFrustum::INTERSECT;
        return;
    } else if (_nextIndex < NUMBER_OF_CHILDREN) {
        EntityTreeElementPointer element = _weakElement.lock();
        if (element) {
            while (_nextIndex < NUMBER_OF_CHILDREN) {
                EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
                ++_nextIndex;
                if (nextElement) {
                    AACube cube = nextElement->getAACube();
                    // check for LOD truncation
                    float distance = glm::distance(view.viewFrustum.getPosition(), cube.calcCenter()) + MIN_VISIBLE_DISTANCE;
                    float angularDiameter = cube.getScale() / distance;
                    if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) {
                        if (view.viewFrustum.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE) {
                            next.element = nextElement;
                            next.intersection = ViewFrustum::OUTSIDE;
                            return;
                        }
                    }
                }
            }
        }
    }
    next.element.reset();
    next.intersection = ViewFrustum::OUTSIDE;
}
Example #3
0
UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
                        EntityTreeElementPointer containingElement,
                        EntityItemPointer existingEntity,
                        const AACube newQueryAACube) :
    _tree(tree),
    _existingEntity(existingEntity),
    _containingElement(containingElement),
    _containingElementCube(containingElement->getAACube()),
    _entityItemID(existingEntity->getEntityItemID()),
    _foundOld(false),
    _foundNew(false),
    _removeOld(false),
    _changeTime(usecTimestampNow()),
    _oldEntityCube(),
    _newEntityCube(),
    _wantDebug(false)
{
    // caller must have verified existence of containingElement and oldEntity
    assert(_containingElement && _existingEntity);

    if (_wantDebug) {
        qCDebug(entities) << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------";
    }

    // Here we have a choice to make, do we want to "tight fit" the actual minimum for the
    // entity into the the element, or do we want to use the entities "relaxed" bounds
    // which can handle all potential rotations?
    // the getMaximumAACube is the relaxed form.
    _oldEntityCube = _existingEntity->getQueryAACube();
    _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds

    _newEntityCube = newQueryAACube;
    _newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds

    // set oldElementBestFit true if the entity was in the correct element before this operator was run.
    bool oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox);

    // For some reason we've seen a case where the original containing element isn't a best fit for the old properties
    // in this case we want to move it, even if the properties haven't changed.
    if (!oldElementBestFit) {
        _oldEntityBox = _existingEntity->getElement()->getAACube();
        _removeOld = true; // our properties are going to move us, so remember this for later processing

        if (_wantDebug) {
            qCDebug(entities) << "    **** UNUSUAL CASE ****  not best fit.... **";
        }
    }

    if (_wantDebug) {
        qCDebug(entities) << "    _entityItemID:" << _entityItemID;
        qCDebug(entities) << "    _containingElementCube:" << _containingElementCube;
        qCDebug(entities) << "    _oldEntityCube:" << _oldEntityCube;
        qCDebug(entities) << "    _oldEntityBox:" << _oldEntityBox;
        qCDebug(entities) << "    _newEntityCube:" << _newEntityCube;
        qCDebug(entities) << "    _newEntityBox:" << _newEntityBox;
        qCDebug(entities) << "--------------------------------------------------------------------------";
    }

}
Example #4
0
void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::VisibleElement& next,
        const DiffTraversal::View& view) {
    // NOTE: no need to set next.intersection in the "FirstTime" context
    if (_nextIndex == -1) {
        // root case is special:
        // its intersection is always INTERSECT,
        // we never bother checking for LOD culling, and
        // we can skip it if the content hasn't changed
        ++_nextIndex;
        next.element = _weakElement.lock();
        return;
    } else if (_nextIndex < NUMBER_OF_CHILDREN) {
        EntityTreeElementPointer element = _weakElement.lock();
        if (element) {
            while (_nextIndex < NUMBER_OF_CHILDREN) {
                EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
                ++_nextIndex;
                if (nextElement) {
                    if (!view.usesViewFrustum) {
                        // No LOD truncation if we aren't using the view frustum
                        next.element = nextElement;
                        return;
                    } else if (view.viewFrustum.cubeIntersectsKeyhole(nextElement->getAACube())) {
                        // check for LOD truncation
                        float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE;
                        float angularDiameter = nextElement->getAACube().getScale() / distance;
                        if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) {
                            next.element = nextElement;
                            return;
                        }
                    }
                }
            }
        }
    }
    next.element.reset();
}
Example #5
0
void DiffTraversal::Waypoint::getNextVisibleElementRepeat(
        DiffTraversal::VisibleElement& next, const DiffTraversal::View& view, uint64_t lastTime) {
    if (_nextIndex == -1) {
        // root case is special
        ++_nextIndex;
        EntityTreeElementPointer element = _weakElement.lock();
        if (element->getLastChangedContent() > lastTime) {
            next.element = element;
            next.intersection = ViewFrustum::INTERSECT;
            return;
        }
    }
    if (_nextIndex < NUMBER_OF_CHILDREN) {
        EntityTreeElementPointer element = _weakElement.lock();
        if (element) {
            while (_nextIndex < NUMBER_OF_CHILDREN) {
                EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
                ++_nextIndex;
                if (nextElement && nextElement->getLastChanged() > lastTime) {
                    if (!view.usesViewFrustum) {
                        // No LOD truncation if we aren't using the view frustum
                        next.element = nextElement;
                        next.intersection = ViewFrustum::INSIDE;
                        return;
                    } else {
                        // check for LOD truncation
                        float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE;
                        float angularDiameter = nextElement->getAACube().getScale() / distance;
                        if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) {
                            ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube());
                            if (intersection != ViewFrustum::OUTSIDE) {
                                next.element = nextElement;
                                next.intersection = intersection;
                                return;
                            }
                        }
                    }
                }
            }
        }
    }
    next.element.reset();
    next.intersection = ViewFrustum::OUTSIDE;
}
UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
                        EntityTreeElementPointer containingElement,
                        EntityItemPointer existingEntity,
                        const EntityItemProperties& properties) :
    _tree(tree),
    _existingEntity(existingEntity),
    _containingElement(containingElement),
    _containingElementCube(containingElement->getAACube()),
    _properties(properties),
    _entityItemID(existingEntity->getEntityItemID()),
    _foundOld(false),
    _foundNew(false),
    _removeOld(false),
    _dontMove(false), // assume we'll be moving
    _changeTime(usecTimestampNow()),
    _oldEntityCube(),
    _newEntityCube(),
    _wantDebug(false)
{
    // caller must have verified existence of containingElement and oldEntity
    assert(_containingElement && _existingEntity);

    if (_wantDebug) {
        qCDebug(entities) << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------";
    }

    // Here we have a choice to make, do we want to "tight fit" the actual minimum for the
    // entity into the the element, or do we want to use the entities "relaxed" bounds
    // which can handle all potential rotations?
    // the getMaximumAACube is the relaxed form.
    _oldEntityCube = _existingEntity->getMaximumAACube();
    _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds

    // If the old properties doesn't contain the properties required to calculate a bounding box,
    // get them from the existing entity. Registration point is required to correctly calculate
    // the bounding box.
    if (!_properties.registrationPointChanged()) {
        _properties.setRegistrationPoint(_existingEntity->getRegistrationPoint());
    }
    
    // If the new properties has position OR dimension changes, but not both, we need to
    // get the old property value and set it in our properties in order for our bounds
    // calculations to work.
    if (_properties.containsPositionChange() && !_properties.containsDimensionsChange()) {
        glm::vec3 oldDimensions= _existingEntity->getDimensions();
        _properties.setDimensions(oldDimensions);

        if (_wantDebug) {
            qCDebug(entities) << "    ** setting properties dimensions - had position change, no dimension change **";
        }

    }
    if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) {
        glm::vec3 oldPosition= _existingEntity->getPosition();
        _properties.setPosition(oldPosition);

        if (_wantDebug) {
            qCDebug(entities) << "    ** setting properties position - had dimensions change, no position change **";
        }
    }

    // If our new properties don't have bounds details (no change to position, etc) or if this containing element would 
    // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will 
    // be the same for both parts of the update
    bool oldElementBestFit = _containingElement->bestFitBounds(_properties);
    
    // if we don't have bounds properties, then use our old clamped box to determine best fit
    if (!_properties.containsBoundsProperties()) {
        oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox);

        if (_wantDebug) {
            qCDebug(entities) << "    ** old Element best fit - no dimensions change, no position change **";
        }

    }
    
    // For some reason we've seen a case where the original containing element isn't a best fit for the old properties
    // in this case we want to move it, even if the properties haven't changed.
    if (!_properties.containsBoundsProperties() && !oldElementBestFit) {
        _newEntityCube = _oldEntityCube;
        _removeOld = true; // our properties are going to move us, so remember this for later processing

        if (_wantDebug) {
            qCDebug(entities) << "    **** UNUSUAL CASE ****  no changes, but not best fit... consider it a move.... **";
        }


    } else if (!_properties.containsBoundsProperties() || oldElementBestFit) {
        _foundOld = true;
        _newEntityCube = _oldEntityCube;
        _dontMove = true;

        if (_wantDebug) {
            qCDebug(entities) << "    **** TYPICAL NO MOVE CASE ****";
            qCDebug(entities) << "        _properties.containsBoundsProperties():" << _properties.containsBoundsProperties();
            qCDebug(entities) << "                             oldElementBestFit:" << oldElementBestFit;
        }

    } else {
        _newEntityCube = _properties.getMaximumAACube();
        _removeOld = true; // our properties are going to move us, so remember this for later processing

        if (_wantDebug) {
            qCDebug(entities) << "    **** TYPICAL MOVE CASE ****";
        }
    }

    _newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds


    if (_wantDebug) {
        qCDebug(entities) << "    _entityItemID:" << _entityItemID;
        qCDebug(entities) << "    _containingElementCube:" << _containingElementCube;
        qCDebug(entities) << "    _oldEntityCube:" << _oldEntityCube;
        qCDebug(entities) << "    _oldEntityBox:" << _oldEntityBox;
        qCDebug(entities) << "    _newEntityCube:" << _newEntityCube;
        qCDebug(entities) << "    _newEntityBox:" << _newEntityBox;
        qCDebug(entities) << "--------------------------------------------------------------------------";
    }

}
bool MovingEntitiesOperator::preRecursion(const OctreeElementPointer& element) {
    EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
    
    // In Pre-recursion, we're generally deciding whether or not we want to recurse this
    // path of the tree. For this operation, we want to recurse the branch of the tree if
    // any of the following are true:
    //   * We have not yet found the old entity, and this branch contains our old entity
    //   * We have not yet found the new entity, and this branch contains our new entity
    //
    // Note: it's often the case that the branch in question contains both the old entity
    // and the new entity.
    
    bool keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);

    // If we haven't yet found all the entities, and this sub tree contains at least one of our
    // entities, then we need to keep searching.
    if (keepSearching && shouldRecurseSubTree(element)) {

        // check against each of our search entities
        int detailIndex = 0;
        foreach(const EntityToMoveDetails& details, _entitiesToMove) {
        
            if (_wantDebug) {
                qCDebug(entities) << "MovingEntitiesOperator::preRecursion() details["<< detailIndex <<"]-----------------------------";
                qCDebug(entities) << "    entityTreeElement:" << entityTreeElement->getAACube();
                qCDebug(entities) << "    entityTreeElement->bestFitBounds(details.newCube):" << entityTreeElement->bestFitBounds(details.newCube);
                qCDebug(entities) << "    details.entity:" << details.entity->getEntityItemID();
                qCDebug(entities) << "    details.oldContainingElementCube:" << details.oldContainingElementCube;
                qCDebug(entities) << "    entityTreeElement:" << entityTreeElement.get();
                qCDebug(entities) << "    details.newCube:" << details.newCube;
                qCDebug(entities) << "    details.newCubeClamped:" << details.newCubeClamped;
                qCDebug(entities) << "    _lookingCount:" << _lookingCount;
                qCDebug(entities) << "    _foundOldCount:" << _foundOldCount;
                qCDebug(entities) << "--------------------------------------------------------------------------";
            }
        

            // If this is one of the old elements we're looking for, then ask it to remove the old entity
            if (!details.oldFound && entityTreeElement == details.oldContainingElement) {
                // DO NOT remove the entity here.  It will be removed when added to the destination element.
                _foundOldCount++;
                //details.oldFound = true; // TODO: would be nice to add this optimization
                if (_wantDebug) {
                    qCDebug(entities) << "MovingEntitiesOperator::preRecursion() -----------------------------";
                    qCDebug(entities) << "    FOUND OLD - REMOVING";
                    qCDebug(entities) << "    entityTreeElement == details.oldContainingElement";
                    qCDebug(entities) << "--------------------------------------------------------------------------";
                }
            }

            // If this element is the best fit for the new bounds of this entity then add the entity to the element
            if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) {
                // remove from the old before adding
                EntityTreeElementPointer oldElement = details.entity->getElement();
                if (oldElement != entityTreeElement) {
                    if (oldElement) {
                        oldElement->removeEntityItem(details.entity);
                    }
                    entityTreeElement->addEntityItem(details.entity);
                } else {
                    entityTreeElement->bumpChangedContent();
                }
                _foundNewCount++;
                //details.newFound = true; // TODO: would be nice to add this optimization
                if (_wantDebug) {
                    qCDebug(entities) << "MovingEntitiesOperator::preRecursion() -----------------------------";
                    qCDebug(entities) << "    FOUND NEW - ADDING";
                    qCDebug(entities) << "    entityTreeElement->bestFitBounds(details.newCube)";
                    qCDebug(entities) << "--------------------------------------------------------------------------";
                }
            }
            detailIndex++;
        }
        // if we haven't found all of our search for entities, then keep looking
        keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);
    }