overte/libraries/entities/src/DeleteEntityOperator.cpp
2018-02-09 12:00:08 -08:00

132 lines
5.4 KiB
C++

//
// DeleteEntityOperator.cpp
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on 8/11/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntityItem.h"
#include "EntityTree.h"
#include "EntityTreeElement.h"
#include "EntitiesLogging.h"
#include "DeleteEntityOperator.h"
DeleteEntityOperator::DeleteEntityOperator(EntityTreePointer tree, const EntityItemID& searchEntityID) :
_tree(tree),
_changeTime(usecTimestampNow()),
_foundCount(0),
_lookingCount(0)
{
addEntityIDToDeleteList(searchEntityID);
}
DeleteEntityOperator::~DeleteEntityOperator() {
}
DeleteEntityOperator::DeleteEntityOperator(EntityTreePointer tree) :
_tree(tree),
_changeTime(usecTimestampNow()),
_foundCount(0),
_lookingCount(0)
{
}
void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID) {
// check our tree, to determine if this entity is known
EntityToDeleteDetails details;
details.containingElement = _tree->getContainingElement(searchEntityID);
if (details.containingElement) {
details.entity = details.containingElement->getEntityWithEntityItemID(searchEntityID);
if (!details.entity) {
//assert(false);
qCDebug(entities) << "that's UNEXPECTED, we got a _containingElement, but couldn't find the oldEntity!";
} else {
details.cube = details.containingElement->getAACube();
_entitiesToDelete << details;
_lookingCount++;
}
}
}
// does this entity tree element contain the old entity
bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(const OctreeElementPointer& element) {
bool containsEntity = false;
// If we don't have an old entity, then we don't contain the entity, otherwise
// check the bounds
if (_entitiesToDelete.size() > 0) {
const AACube& elementCube = element->getAACube();
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
if (elementCube.contains(details.cube)) {
containsEntity = true;
break; // if it contains at least one, we're good to go
}
}
}
return containsEntity;
}
bool DeleteEntityOperator::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:
// * We have not yet found the all entities, and
// * this branch contains our some of the entities we're looking for.
bool keepSearching = false; // assume we don't need to search any more
// 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 ((_foundCount < _lookingCount) && subTreeContainsSomeEntitiesToDelete(element)) {
// check against each of our search entities
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
// If this is the element we're looking for, then ask it to remove the old entity
// and we can stop searching.
if (entityTreeElement == details.containingElement) {
EntityItemPointer theEntity = details.entity;
bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element
assert(entityDeleted);
(void)entityDeleted; // quite warning
_tree->clearEntityMapEntry(details.entity->getEntityItemID());
_foundCount++;
}
}
// if we haven't found all of our search for entities, then keep looking
keepSearching = (_foundCount < _lookingCount);
}
return keepSearching; // if we haven't yet found it, keep looking
}
bool DeleteEntityOperator::postRecursion(const OctreeElementPointer& element) {
// Post-recursion is the unwinding process. For this operation, while we
// unwind we want to mark the path as being dirty if we changed it below.
// We might have two paths, one for the old entity and one for the new entity.
bool keepSearching = (_foundCount < _lookingCount);
// As we unwind, if we're in either of these two paths, we mark our element
// as dirty.
if ((subTreeContainsSomeEntitiesToDelete(element))) {
element->markWithChangedTime();
}
// It should always be ok to prune children. Because we are only in this PostRecursion function if
// we've already finished processing all of the children of this current element. If any of those
// children are the containing element for any entity in our lists of entities to delete, then they
// must have already deleted the entity, and they are safe to prune. Since this operation doesn't
// ever add any elements we don't have to worry about memory being reused within this recursion pass.
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves
return keepSearching; // if we haven't yet found it, keep looking
}