Commit 6c67f92f authored by David Thompson's avatar David Thompson
Browse files

Implement `ModelEntity::remove{Cell,Group,Submodel}.

parent 6066f5c1
......@@ -705,31 +705,8 @@ Cursor Cursor::relationFromArrangement(
*/
Cursor& Cursor::embedEntity(const Cursor& thingToEmbed)
{
StorageEventType event = std::make_pair(ADD_EVENT, INVALID_RELATIONSHIP);
switch (this->entityFlags() & ENTITY_MASK)
{
case MODEL_ENTITY:
switch (thingToEmbed.entityFlags() & ENTITY_MASK)
{
case SHELL_ENTITY: event.second = MODEL_INCLUDES_FREE_SHELL; break;
case CELL_ENTITY: event.second = MODEL_INCLUDES_FREE_CELL; break;
case USE_ENTITY: event.second = MODEL_INCLUDES_FREE_USE; break;
}
break;
case CELL_ENTITY:
switch (thingToEmbed.entityFlags() & ENTITY_MASK)
{
case CELL_ENTITY: event.second = CELL_INCLUDES_CELL; break;
}
break;
case SHELL_ENTITY:
switch (thingToEmbed.entityFlags() & ENTITY_MASK)
{
case SHELL_ENTITY: event.second = SHELL_INCLUDES_SHELL; break;
case USE_ENTITY: event.second = SHELL_HAS_USE; break;
}
break;
}
//StorageEventType event = std::make_pair(ADD_EVENT, INVALID_RELATIONSHIP);
StorageEventType event = std::make_pair(ADD_EVENT, this->embeddingRelationType(thingToEmbed));
if (event.second != INVALID_RELATIONSHIP)
{
CursorArrangementOps::findOrAddSimpleRelationship(*this, INCLUDES, thingToEmbed);
......@@ -739,6 +716,26 @@ Cursor& Cursor::embedEntity(const Cursor& thingToEmbed)
return *this;
}
/**\brief Unembed the specified \a thingToUnembed as an inclusion into this cursor's entity.
*
* This removes an INCLUDES relation (if necessary) to this entity and
* an EMBEDDED_IN relation (if necessary) to the \a thingToUnembed.
*/
Cursor& Cursor::unembedEntity(const Cursor& thingToEmbed)
{
StorageEventType event = std::make_pair(DEL_EVENT, this->embeddingRelationType(thingToEmbed));
if (event.second != INVALID_RELATIONSHIP)
{
int aidx = CursorArrangementOps::findSimpleRelationship(*this, INCLUDES, thingToEmbed);
if (aidx >= 0)
{
this->m_storage->unarrangeEntity(this->m_entity, EMBEDDED_IN, aidx);
this->m_storage->trigger(event, *this, thingToEmbed);
}
}
return *this;
}
/**\brief Return whether the specified \a entity is a direct inclusion in this cursor's entity.
*
*/
......@@ -780,6 +777,38 @@ bool Cursor::operator < (const Cursor& other) const
return this->m_entity < other.m_entity;
}
StorageEventRelationType Cursor::embeddingRelationType(const Cursor& embedded) const
{
StorageEventRelationType reln = INVALID_RELATIONSHIP;
switch (this->entityFlags() & ENTITY_MASK)
{
case MODEL_ENTITY:
switch (embedded.entityFlags() & ENTITY_MASK)
{
case SHELL_ENTITY: reln = MODEL_INCLUDES_FREE_SHELL; break;
case CELL_ENTITY: reln = MODEL_INCLUDES_FREE_CELL; break;
case USE_ENTITY: reln = MODEL_INCLUDES_FREE_USE; break;
}
break;
case CELL_ENTITY:
switch (embedded.entityFlags() & ENTITY_MASK)
{
case CELL_ENTITY: reln = CELL_INCLUDES_CELL; break;
}
break;
case SHELL_ENTITY:
switch (embedded.entityFlags() & ENTITY_MASK)
{
case SHELL_ENTITY: reln = SHELL_INCLUDES_SHELL; break;
case USE_ENTITY: reln = SHELL_HAS_USE; break;
}
break;
}
return reln;
}
std::ostream& operator << (std::ostream& os, const Cursor& c)
{
os << c.name();
......
......@@ -185,6 +185,9 @@ public:
bool isEmbedded(Cursor& entity) const;
Cursor embeddedIn() const;
Cursor& unembedEntity(const Cursor& thingToUnembed);
template<typename T> Cursor& unembedEntities(const T& container);
template<typename T> T instances() const;
bool operator == (const Cursor& other) const;
......@@ -193,6 +196,10 @@ public:
protected:
StoragePtr m_storage;
smtk::util::UUID m_entity;
// When embedding/unembedding, this method determines the relationship type
// based on the entities involved.
StorageEventRelationType embeddingRelationType(const Cursor& embedded) const;
};
SMTKCORE_EXPORT std::ostream& operator << (std::ostream& os, const Cursor& c);
......@@ -221,6 +228,15 @@ template<typename T> Cursor& Cursor::embedEntities(const T& container)
return *this;
}
template<typename T> Cursor& Cursor::unembedEntities(const T& container)
{
for (typename T::const_iterator it = container.begin(); it != container.end(); ++it)
{
this->unembedEntity(*it);
}
return *this;
}
} // namespace model
} // namespace smtk
......
......@@ -22,10 +22,12 @@ namespace smtk {
* affect storage are typically reported with
* ADD_EVENT notifications generated before addition
* and DEL_EVENT notifications after removal.
* The rationale is that observers should have
* The rationale is that (1) observers should have
* direct access to the most difficult-to-infer
* configuration while the event type specifies enough
* information to infer the simpler configuration.
* information to infer the simpler configuration and
* (2) observers may wish to perform other operations
* after removal to maintain the consistency of Storage.
*
* Events that add new smtk::model::Entity, smtk::model::Tessellation,
* smtk::model::FloatData, smtk::model::StringData, or
......
......@@ -43,6 +43,12 @@ ModelEntity& ModelEntity::addCell(const CellEntity& c)
return *this;
}
ModelEntity& ModelEntity::removeCell(const CellEntity& c)
{
this->unembedEntity(c);
return *this;
}
ModelEntity& ModelEntity::addGroup(const GroupEntity& g)
{
if (this->isValid() && g.isValid())
......@@ -54,6 +60,19 @@ ModelEntity& ModelEntity::addGroup(const GroupEntity& g)
return *this;
}
ModelEntity& ModelEntity::removeGroup(const GroupEntity& g)
{
if (this->isValid() && g.isValid())
{
int aidx = CursorArrangementOps::findSimpleRelationship(*this, SUPERSET_OF, g);
if (aidx >= 0 && this->m_storage->unarrangeEntity(this->m_entity, SUPERSET_OF, aidx) > 0)
{
this->m_storage->trigger(StorageEventType(DEL_EVENT, MODEL_INCLUDES_GROUP), *this, g);
}
}
return *this;
}
ModelEntity& ModelEntity::addSubmodel(const ModelEntity& m)
{
if (this->isValid() && m.isValid() && m.storage() == this->storage() && m.entity() != this->entity())
......@@ -65,5 +84,18 @@ ModelEntity& ModelEntity::addSubmodel(const ModelEntity& m)
return *this;
}
ModelEntity& ModelEntity::removeSubmodel(const ModelEntity& m)
{
if (this->isValid() && m.isValid() && m.storage() == this->storage() && m.entity() != this->entity())
{
int aidx = CursorArrangementOps::findSimpleRelationship(*this, SUPERSET_OF, m);
if (aidx >= 0 && this->m_storage->unarrangeEntity(this->m_entity, SUPERSET_OF, aidx) > 0)
{
this->m_storage->trigger(StorageEventType(DEL_EVENT, MODEL_INCLUDES_MODEL), *this, m);
}
}
return *this;
}
} // namespace model
} // namespace smtk
......@@ -28,13 +28,19 @@ public:
ModelEntities submodels() const;
ModelEntity& addCell(const CellEntity& c);
ModelEntity& removeCell(const CellEntity& c);
template<typename T> ModelEntity& addCells(const T& container);
template<typename T> ModelEntity& removeCells(const T& container);
ModelEntity& addGroup(const GroupEntity& g);
ModelEntity& removeGroup(const GroupEntity& g);
template<typename T> ModelEntity& addGroups(const T& container);
template<typename T> ModelEntity& removeGroups(const T& container);
ModelEntity& addSubmodel(const ModelEntity& m);
ModelEntity& removeSubmodel(const ModelEntity& m);
template<typename T> ModelEntity& addSubmodels(const T& container);
template<typename T> ModelEntity& removeSubmodels(const T& container);
};
/// Add all the free cells in \a container to this model.
......@@ -44,17 +50,50 @@ template<typename T> ModelEntity& ModelEntity::addCells(const T& container)
return *this;
}
/// Add all the free cells in \a container to this model.
template<typename T> ModelEntity& ModelEntity::removeCells(const T& container)
{
this->unembedEntities(container);
return *this;
}
/// Add all the groups in \a container to this model.
template<typename T> ModelEntity& ModelEntity::addGroups(const T& container)
{
this->embedEntities(container);
for (typename T::const_iterator it = container.begin(); it != container.end(); ++it)
{
this->addGroup(*it);
}
return *this;
}
/// Add all the groups in \a container to this model.
template<typename T> ModelEntity& ModelEntity::removeGroups(const T& container)
{
for (typename T::const_iterator it = container.begin(); it != container.end(); ++it)
{
this->removeGroup(*it);
}
return *this;
}
/// Add all the models in \a container as submodels to this model.
template<typename T> ModelEntity& ModelEntity::addSubmodels(const T& container)
{
this->embedEntities(container);
for (typename T::const_iterator it = container.begin(); it != container.end(); ++it)
{
this->addSubmodel(*it);
}
return *this;
}
/// Add all the models in \a container as submodels to this model.
template<typename T> ModelEntity& ModelEntity::removeSubmodels(const T& container)
{
for (typename T::const_iterator it = container.begin(); it != container.end(); ++it)
{
this->removeSubmodel(*it);
}
return *this;
}
......
......@@ -29,6 +29,24 @@ using namespace smtk::model;
using namespace smtk::model::testing;
using smtk::shared_ptr;
static int numberOfInclusionsRemoved = 0;
static int numberOfFreeCellsRemoved = 0;
static int numberOfSubmodelsRemoved = 0;
static int numberOfGroupsRemoved = 0;
int didRemove(StorageEventType event, const Cursor&, const Cursor&, void*)
{
switch (event.second)
{
case MODEL_INCLUDES_MODEL: ++numberOfSubmodelsRemoved; break;
case MODEL_INCLUDES_GROUP: ++numberOfGroupsRemoved; break;
case MODEL_INCLUDES_FREE_CELL: ++numberOfFreeCellsRemoved; break;
case CELL_INCLUDES_CELL: ++numberOfInclusionsRemoved; break;
default: break;
}
return 0;
}
void testComplexVertexChain()
{
StoragePtr sm = Storage::create();
......@@ -82,6 +100,11 @@ int main(int argc, char* argv[])
try
{
StoragePtr sm = Storage::create();
sm->observe(StorageEventType(DEL_EVENT, CELL_INCLUDES_CELL), didRemove, NULL);
sm->observe(StorageEventType(DEL_EVENT, MODEL_INCLUDES_FREE_CELL), didRemove, NULL);
sm->observe(StorageEventType(DEL_EVENT, MODEL_INCLUDES_GROUP), didRemove, NULL);
sm->observe(StorageEventType(DEL_EVENT, MODEL_INCLUDES_MODEL), didRemove, NULL);
UUIDArray uids = createTet(sm);
ModelEntity model = sm->addModel(3, 3, "TestModel");
......@@ -276,6 +299,26 @@ int main(int argc, char* argv[])
vol.inclusions<CellEntities>()[0] == v,
"Volume should have an included vertex.");
// Test removing cell inclusions and model members.
// a. Cell inclusion
vol.unembedEntity(v);
test(numberOfInclusionsRemoved == 1, "Did not unembed vertex from volume");
// b. Free cell in model
model.addCell(v);
model.removeCell(v);
test(numberOfFreeCellsRemoved == 1, "Did not remove free vertex from model");
// c. Group in model
model.removeGroup(bits);
test(numberOfGroupsRemoved == 1, "Did not remove group from model");
// d. Submodel of model
ModelEntity submodel = sm->addModel(3, 3, "Surplus model");
model.addSubmodel(submodel);
model.removeSubmodel(submodel);
test(numberOfSubmodelsRemoved == 1, "Did not remove submodel from model");
// Test Volume::shells()
Shells shells = vol.shells();
test(shells == vol.use().shells(), "Volume::use() test failed.");
......
......@@ -33,6 +33,10 @@
<suppress-warning text="skipping function 'smtk::model::Cursor::instances', unmatched return type 'T'"/>
<suppress-warning text="skipping function 'smtk::model::GroupEntity::addEntities', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::ModelEntity::addSubmodels', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::ModelEntity::removeSubmodels', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::ModelEntity::removeGroups', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::ModelEntity::removeCells', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::Cursor::unembedEntities', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::model::ShellEntity::addUses', unmatched parameter type 'T const&amp;'"/>
<suppress-warning text="skipping function 'smtk::attribute::Attribute::associatedModelEntities', unmatched return type 'T'"/>
......@@ -220,6 +224,7 @@
<suppress-warning text="skipping function 'smtk::model::Storage::unobserve', unmatched parameter type 'smtk::model::OneToOneCallback'"/>
<suppress-warning text="skipping field 'DescriptivePhrase::m_parent' with unmatched type 'smtk::weak_ptr&lt;smtk::model::DescriptivePhrase&gt;'"/>
@EXTRA_TYPESYSTEMS@
<primitive-type name="bool"/>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment