Skip to content

Commit

Permalink
#5643: Extend INamespace interface by a method that only covers a sub…
Browse files Browse the repository at this point in the history
…set of the to-be-imported scene.
  • Loading branch information
codereader committed Jun 18, 2021
1 parent 5cd128a commit 0ab693c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 19 deletions.
13 changes: 12 additions & 1 deletion include/inamespace.h
@@ -1,5 +1,6 @@
#pragma once

#include <set>
#include "inode.h"
#include "imodule.h"

Expand Down Expand Up @@ -91,7 +92,17 @@ class INamespace
* \em not actually import the given scene graph's names into this
* namespace.
*/
virtual void ensureNoConflicts(const scene::INodePtr& root) = 0;
virtual void ensureNoConflicts(const scene::INodePtr& foreignRoot) = 0;

/**
* Specialised variant of the above ensureNoConflicts(foreignRoot):
* Prepares only the given list of nodes (that are member of the foreign root) such that
* their names don't conflict with any name in this namespace.
*
* Every Namespaced node will get a new unique name assigned, but only if it's
* actually colliding with a local name, otherwise it will remain unchanged.
*/
virtual void ensureNoConflicts(const scene::INodePtr& foreignRoot, const std::set<scene::INodePtr>& foreignNodes) = 0;
};
typedef std::shared_ptr<INamespace> INamespacePtr;

Expand Down
57 changes: 40 additions & 17 deletions radiantcore/map/namespace/Namespace.cpp
Expand Up @@ -242,20 +242,43 @@ void Namespace::nameChanged(const std::string& oldName, const std::string& newNa
}
}

void Namespace::ensureNoConflicts(const scene::INodePtr& root)
void Namespace::ensureNoConflicts(const scene::INodePtr& foreignRoot)
{
// Collect all namespaced items from the foreign root
GatherNamespacedWalker walker;
foreignRoot->traverse(walker);

ensureNoConflicts(foreignRoot, walker.result);
}

void Namespace::ensureNoConflicts(const scene::INodePtr& foreignRoot, const std::set<scene::INodePtr>& foreignNodes)
{
// Filter out all namespaced items from the given scene node list
std::set<NamespacedPtr> foreignItems;

for (const auto& node : foreignNodes)
{
auto namespaced = Node_getNamespaced(node);

if (namespaced)
{
foreignItems.emplace(std::move(namespaced));
}
}

ensureNoConflicts(foreignRoot, foreignItems);
}

void Namespace::ensureNoConflicts(const scene::INodePtr& foreignRoot, const std::set<NamespacedPtr>& foreignNodes)
{
// Instantiate a new, temporary namespace for the nodes below root
Namespace foreignNamespace;

// Move all nodes below (and including) root into this temporary namespace
foreignNamespace.connect(root);

// Collect all namespaced items from the foreign root
GatherNamespacedWalker walker;
root->traverse(walker);
foreignNamespace.connect(foreignRoot);

rDebug() << "Namespace::ensureNoConflicts(): imported set of "
<< walker.result.size() << " namespaced nodes" << std::endl;
rDebug() << "Namespace::ensureNoConflicts(): importing set of "
<< foreignNodes.size() << " namespaced nodes" << std::endl;

// Build a union set containing all imported names and all existing names.
// We need to know all existing names to ensure that newly created names are
Expand All @@ -265,29 +288,29 @@ void Namespace::ensureNoConflicts(const scene::INodePtr& root)

// Process each object in the to-be-imported tree of nodes, ensuring that it
// has a unique name
for (const NamespacedPtr& n : walker.result)
for (const auto& foreignNode : foreignNodes)
{
// If the imported node conflicts with a name in THIS namespace, then it
// needs to be given a new name which is unique in BOTH namespaces.
if (_uniqueNames.nameExists(n->getName()))
if (_uniqueNames.nameExists(foreignNode->getName()))
{
// Name exists in the target namespace, get a new name
std::string uniqueName = allNames.insertUnique(n->getName());
std::string uniqueName = allNames.insertUnique(foreignNode->getName());

rMessage() << "Namespace::ensureNoConflicts(): '" << n->getName()
<< "' already exists in this namespace. Rename it to '"
<< uniqueName << "'\n";
rMessage() << "Namespace::ensureNoConflicts(): '" << foreignNode->getName()
<< "' already exists in this namespace. Rename it to '"
<< uniqueName << "'\n";

// Change the name of the imported node, this should trigger all
// observers in the foreign namespace
n->changeName(uniqueName);
foreignNode->changeName(uniqueName);
}
else
{
// Name does not exist yet, insert it into the local combined
// namespace (but not our destination namespace, this will be
// populated in the subsequent call to connect()).
allNames.insert(n->getName());
allNames.insert(foreignNode->getName());
}
}

Expand All @@ -296,5 +319,5 @@ void Namespace::ensureNoConflicts(const scene::INodePtr& root)
// nodes into this namespace without name conflicts

// Disconnect the root from the foreign namespace again, it will be destroyed now
foreignNamespace.disconnect(root);
foreignNamespace.disconnect(foreignRoot);
}
7 changes: 6 additions & 1 deletion radiantcore/map/namespace/Namespace.h
Expand Up @@ -9,6 +9,7 @@
class Namespace :
public INamespace
{
private:
// The set of unique names in this namespace
UniqueNameSet _uniqueNames;

Expand All @@ -29,5 +30,9 @@ class Namespace :
virtual void addNameObserver(const std::string& name, NameObserver& observer) override;
virtual void removeNameObserver(const std::string& name, NameObserver& observer) override;
virtual void nameChanged(const std::string& oldName, const std::string& newName) override;
virtual void ensureNoConflicts(const scene::INodePtr& root) override;
virtual void ensureNoConflicts(const scene::INodePtr& foreignRoot) override;
virtual void ensureNoConflicts(const scene::INodePtr& foreignRoot, const std::set<scene::INodePtr>& foreignNodes) override;

private:
void ensureNoConflicts(const scene::INodePtr& foreignRoot, const std::set<NamespacedPtr>& foreignNodes);
};

0 comments on commit 0ab693c

Please sign in to comment.