Abstract out globalizeProperties.

This commit is contained in:
howard-stearns 2016-03-29 15:21:06 -07:00
parent 4a28dadae5
commit bcb729eac2
4 changed files with 43 additions and 72 deletions

View file

@ -2792,7 +2792,7 @@ void Application::calibrateEyeTracker5Points() {
#endif
bool Application::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) {
class EntityDatum { // For parent-first sorting and mapping.
/* class EntityDatum { // For parent-first sorting and mapping.
public:
EntityItemPointer item;
EntityItemProperties properties;
@ -2803,7 +2803,8 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
item(itemArg), properties(propertiesArg), originalParentID(parentID) {
};
};
QHash<EntityItemID, EntityDatum> entities;
QHash<EntityItemID, EntityDatum> entities;*/
QHash<EntityItemID, EntityItemPointer> entities;
auto entityTree = getEntities()->getTree();
auto exportTree = std::make_shared<EntityTree>();
@ -2813,66 +2814,34 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
for (auto entityID : entityIDs) { // Gather entities and properties.
auto entityItem = entityTree->findEntityByEntityItemID(entityID);
if (!entityItem) {
qCDebug(interfaceapp) << "Skipping export of" << entityID << "that is not in scene.";
qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene.";
continue;
}
auto properties = entityItem->getProperties();
EntityItemID parentID = properties.getParentID();
if (parentID.isInvalidID() || !entityIDs.contains(parentID)) {
EntityItemID parentID = entityItem->getParentID();
if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) {
auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties.
root.x = glm::min(root.x, position.x);
root.y = glm::min(root.y, position.y);
root.z = glm::min(root.z, position.z);
}
qCDebug(interfaceapp) << "Exporting" << entityItem->getEntityItemID() << entityItem->getName();
entities[entityID] = EntityDatum(entityItem, properties, parentID);
entities[entityID] = entityItem; // EntityDatum(entityItem, entityItem->getProperties(), parentID);
}
if (entities.size() == 0) {
return false;
}
for (EntityDatum& entityDatum : entities) {
// Recursively add the parents of entities to the exportTree, mapping their new identifiers as we go.
std::function<EntityItemID(EntityDatum&)> getMapped = [&](EntityDatum& datum) { // FIXME: move definition outside the loop
auto originalID = datum.item->getEntityItemID();
if (!datum.mappedID.isInvalidID()) {
qCDebug(interfaceapp) << "already mapped" << datum.properties.getName() << originalID << "=>" << datum.mappedID;
return datum.mappedID; // We are a parent that has already been added/mapped.
}
auto properties = datum.properties;
auto parentID = datum.originalParentID;
if (parentID.isInvalidID() || !entityIDs.contains(parentID)) {
bool success;
auto globalPosition = datum.item->getPosition(success);
if (success) {
properties.setPosition(globalPosition - root);
if (!parentID.isInvalidID()) { // There's a parent that we won't output. Make the other data global.
properties.setRotation(datum.item->getRotation());
properties.setDimensions(datum.item->getDimensions());
// Should we do velocities and accelerations, too?
}
} else {
properties.setPosition(datum.item->getQueryAACube().calcCenter() - root); // best we can do
}
} else {// Recurse over ancestors, updating properties.
qCDebug(interfaceapp) << "FIXME recursing" << datum.originalParentID << "parent of" << datum.item->getEntityItemID();
// Warning: could blow the call stack if the parent hierarchy is VERY deep.
parentID = getMapped(entities[parentID]);
properties.setParentID(parentID);
}
datum.mappedID = originalID; // FIXME: simplify because we don't have to map ids.
auto newEntity = exportTree->addEntity(datum.mappedID, properties);
qCDebug(interfaceapp) << "mapped" << properties.getName();
qCDebug(interfaceapp) << " " << originalID << "p:" << datum.originalParentID;
qCDebug(interfaceapp) << " =>" << datum.mappedID << "p:" << parentID;
qCDebug(interfaceapp) << " @" << properties.getPosition() << "/" << properties.getLocalPosition();
return datum.mappedID;
};
getMapped(entityDatum);
//for (EntityDatum& entityDatum : entities) {
for (EntityItemPointer& entityDatum : entities) {
auto properties = entityDatum->getProperties();
EntityItemID parentID = properties.getParentID();
if (parentID.isInvalidID()) {
properties.setPosition(properties.getPosition() - root);
} else if (!entities.contains(parentID)) {
entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root);
} // else valid parent -- don't offset
exportTree->addEntity(entityDatum->getEntityItemID(), properties);
}
exportTree->writeToJSONFile(filename.toLocal8Bit().constData());

View file

@ -1982,3 +1982,25 @@ void EntityItem::dimensionsChanged() {
requiresRecalcBoxes();
SpatiallyNestable::dimensionsChanged(); // Do what you have to do
}
void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const {
bool success;
auto globalPosition = getPosition(success);
if (success) {
properties.setPosition(globalPosition + offset);
properties.setRotation(getRotation());
properties.setDimensions(getDimensions());
// Should we do velocities and accelerations, too? This could end up being quite involved, which is why the method exists.
} else {
properties.setPosition(getQueryAACube().calcCenter() + offset); // best we can do
}
if (!messageTemplate.isEmpty()) {
QString name = properties.getName();
if (name.isEmpty()) {
name = EntityTypes::getEntityTypeName(properties.getType());
}
qCWarning(entities) << messageTemplate.arg(getEntityItemID().toString()).arg(name).arg(properties.getParentID().toString());
}
QUuid empty;
properties.setParentID(empty);
}

View file

@ -86,6 +86,8 @@ public:
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties);
// Update properties with empty parent id and globalized/absolute values (applying offset), and apply (non-empty) log template to args id, name-or-type, parent id.
void globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate = QString(), const glm::vec3& offset = glm::vec3(0.0f)) const;
/// Override this in your derived class if you'd like to be informed when something about the state of the entity
/// has changed. This will be called with properties change or when new data is loaded from a stream

View file

@ -1334,7 +1334,6 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
}
bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) {
qCDebug(entities) << "sendEntitiesOperation";
SendEntitiesOperationArgs* args = static_cast<SendEntitiesOperationArgs*>(extraData);
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
std::function<const EntityItemID(EntityItemPointer&)> getMapped = [&](EntityItemPointer& item) -> const EntityItemID {
@ -1351,33 +1350,14 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra
} else {
EntityItemPointer parentEntity = args->ourTree->findEntityByEntityItemID(oldParentID);
if (parentEntity) { // map the parent
// Warning: could blow the call stack if the parent hierarchy is VERY deep.
// Warning: (non-tail) recursion of getMapped could blow the call stack if the parent hierarchy is VERY deep.
properties.setParentID(getMapped(parentEntity));
// But do not add root offset in this case.
} else { // Should not happen, but let's try to be helpful...
// Log what we can.
QString name = properties.getName();
if (name.isEmpty()) {
name = EntityTypes::getEntityTypeName(properties.getType());
}
bool success;
glm::vec3 position = item->getPosition(success);
qCWarning(entities) << "Cannot find" << oldParentID << "parent of" << oldID << name << (success ? "" : "and unable to resolve geometry");
// Adjust geometry with absolute/global values.
if (success) {
properties.setPosition(position + args->root);
properties.setRotation(item->getRotation());
properties.setDimensions(item->getDimensions());
// Should we do velocities and accelerations, too?
} else {
properties.setPosition(item->getQueryAACube().calcCenter() + args->root); // best we can do
}
QUuid empty;
properties.setParentID(empty);
item->globalizeProperties(properties, "Cannot find %3 parent of %2 %1", args->root);
}
}
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID() << "pos:" << properties.getPosition();
// queue the packet to send to the server
args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties);
@ -1434,12 +1414,10 @@ bool EntityTree::readFromMap(QVariantMap& map) {
}
EntityItemPointer entity = addEntity(entityItemID, properties);
qCDebug(entities) << "HRS FIXME added" << entityItemID << properties.getName() << "@" << properties.getPosition();
if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
}
}
qCDebug(entities) << "HRS FIXME end of readFromMap";
return true;
}