Commit 9009df48 authored by David Thompson's avatar David Thompson
Browse files

Progress on Qt model and cursor implementation.

Expose more relationships in the UI and continue
fleshing out the cursor subclasses.

This implements InstanceEntity methods in a way that
will not conflict with groups.
parent 2df40d63
......@@ -140,6 +140,18 @@ Arrangement Arrangement::ShellEmbeddedInUseOrShellWithIndex(int relationIdx)
{
return Arrangement::SimpleIndex(relationIdx);
}
/// Create a record for an instance indicating the prototype entity it instantiates.
Arrangement Arrangement::InstanceInstanceOfWithIndex(int relationIdx)
{
return Arrangement::SimpleIndex(relationIdx);
}
/// Create a record for an entity indicating that is serves as a prototype for an instance.
Arrangement Arrangement::EntityInstancedByWithIndex(int relationIdx)
{
return Arrangement::SimpleIndex(relationIdx);
}
///@}
/** @name Methods to interpret arrangements.
......@@ -229,6 +241,18 @@ bool Arrangement::IndexFromShellEmbeddedInUseOrShell(int& relationIdx) const
return this->IndexFromSimple(relationIdx);
}
/// Obtain the index of the prototype of which this entity is an instance.
bool Arrangement::IndexFromInstanceInstanceOf(int& relationIdx) const
{
return this->IndexFromSimple(relationIdx);
}
/// Obtain the index of the instance for which this entity is a prototype.
bool Arrangement::IndexFromEntityInstancedBy(int& relationIdx) const
{
return this->IndexFromSimple(relationIdx);
}
/// Create an arrangement holding the index of a single entity ID (a simple arrangement).
Arrangement Arrangement::SimpleIndex(int relationIdx)
{
......
......@@ -48,6 +48,8 @@ public:
static Arrangement ShellHasCellWithIndex(int relationIdx);
static Arrangement ShellHasUseWithIndexRange(int relationBegin, int relationEnd);
static Arrangement ShellEmbeddedInUseOrShellWithIndex(int relationIdx);
static Arrangement InstanceInstanceOfWithIndex(int relationIdx);
static Arrangement EntityInstancedByWithIndex(int relationIdx);
bool IndexSenseAndOrientationFromCellHasUse(int& relationIdx, int& sense, Orientation& orient) const;
bool IndexFromCellEmbeddedInEntity(int& relationIdx) const;
......@@ -59,6 +61,8 @@ public:
bool IndexFromShellHasCell(int& relationIdx) const;
bool IndexRangeFromShellHasUse(int& relationBegin, int& relationEnd) const;
bool IndexFromShellEmbeddedInUseOrShell(int& relationIdx) const;
bool IndexFromInstanceInstanceOf(int& relationIdx) const;
bool IndexFromEntityInstancedBy(int& relationIdx) const;
static Arrangement SimpleIndex(int relationIdx);
bool IndexFromSimple(int& relationIdx) const;
......
......@@ -4,24 +4,28 @@ namespace smtk {
namespace model {
const char* ArrangementKindName[KINDS_OF_ARRANGEMENTS + 1] = {
"inclusion", // INCLUDES
"cell", // HAS_CELL
"shell", // HAS_SHELL
"use", // HAS_USE
"embedding", // EMBEDDED_IN
"subset", // SUBSET_OF
"superset", // SUPERSET_OF
"invalid" // KINDS_OF_ARRANGEMENTS
"inclusion", // INCLUDES
"cell", // HAS_CELL
"shell", // HAS_SHELL
"use", // HAS_USE
"embedding", // EMBEDDED_IN
"subset", // SUBSET_OF
"superset", // SUPERSET_OF
"instantiates", // INSTANCE_OF
"instance", // INSTANCED_BY
"invalid" // KINDS_OF_ARRANGEMENTS
};
const char* ArrangementKindAbbr[KINDS_OF_ARRANGEMENTS + 1] = {
"i", // INCLUSION
"c", // CELL
"s", // SHELL
"u", // ORIENTATION
"e", // EMBEDDING
"b", // SUBSET_OF
"r", // SUPERSET_OF
"i", // INCLUDES
"c", // HAS_CELL
"s", // HAS_SHELL
"u", // HAS_USE
"e", // EMBEDDED_IN
"b", // SUBSET_OF (suBset)
"r", // SUPERSET_OF (supeRset)
"p", // INSTANCE_OF (Prototype)
"x", // INSTANCED_BY (eXemplar)
"?" // KINDS_OF_ARRANGEMENTS
};
......
......@@ -35,14 +35,17 @@ enum Orientation {
/// Specification of how a cell's relations are arranged.
enum ArrangementKind {
// Enums specific to cell, use, and shell relationships:
INCLUDES, //!< How another cell is contained in the interior of this cell.
HAS_CELL, //!< How a use or shell is related to its cell.
HAS_SHELL, //!< How this cell is bounded by cells of lower dimension or how a use participates in a shell.
HAS_USE, //!< How this cell's shells are combined into a single orientation for use by bordant cells.
EMBEDDED_IN, //!< How this cell is embedded in the interior of a cell of higher dimension
INCLUDES, //!< How another cell is contained in the interior of this cell.
HAS_CELL, //!< How a use or shell is related to its cell.
HAS_SHELL, //!< How this cell is bounded by cells of lower dimension or how a use participates in a shell.
HAS_USE, //!< How this cell's shells are combined into a single orientation for use by bordant cells.
EMBEDDED_IN, //!< How this cell is embedded in the interior of a cell of higher dimension
// Enums specific to group relationships:
SUBSET_OF, //!< This entity is a subset of the related entity.
SUPERSET_OF, //!< This entity is a superset of the related entity.
SUBSET_OF, //!< This entity is a subset of the related entity.
SUPERSET_OF, //!< This entity is a superset of the related entity.
// Enums specific to instance relationships:
INSTANCE_OF, //!< This entity is an instance of the related entity.
INSTANCED_BY, //!< This entity has an instance (duplicate) that is the related entity.
//
KINDS_OF_ARRANGEMENTS //!< The number of different kinds of arrangement relationships enumerated here.
};
......
......@@ -14,10 +14,10 @@ namespace smtk {
*/
ModelEntity CellEntity::model() const
{
StoragePtr storage = this->storage();
StoragePtr store = this->storage();
return ModelEntity(
storage,
storage->modelOwningEntity(this->entity()));
store,
store->modelOwningEntity(this->entity()));
}
/**\brief Report the toplevel shell records associated with the cell.
......
......@@ -556,9 +556,9 @@ Cursor& Cursor::embedEntity(const Cursor& thingToEmbed)
/**\brief Return whether the specified \a entity is a direct inclusion in this cursor's entity.
*
*/
bool Cursor::isEmbedded(Cursor& entity) const
bool Cursor::isEmbedded(Cursor& ent) const
{
return CursorArrangementOps::findSimpleRelationship(*this, INCLUDES, entity) >= 0;
return CursorArrangementOps::findSimpleRelationship(*this, INCLUDES, ent) >= 0;
}
/**\brief Report the entity into which this entity is directly embedded.
......@@ -600,5 +600,17 @@ std::ostream& operator << (std::ostream& os, const Cursor& c)
return os;
}
/*! \fn template<typename S, typename T> void Cursor::CursorsFromUUIDs(S& result, StoragePtr storage, const T& uids)
*\brief Convert a set of UUIDs into a set of cursors referencing the same \a storage.
*/
/*! \fn template<typename T> Cursor::embedEntities(const T& container)
* \brief Embed each of the entities in the container inside this entity.
*/
/*! \fn Cursor::instances() const
* \brief Return all the instances this object serves as a prototype for.
*/
} // namespace model
} // namespace smtk
......@@ -170,6 +170,8 @@ public:
bool isEmbedded(Cursor& entity) const;
Cursor embeddedIn() const;
template<typename T> T instances() const;
bool operator == (const Cursor& other) const;
bool operator < (const Cursor& other) const;
......@@ -180,7 +182,6 @@ protected:
SMTKCORE_EXPORT std::ostream& operator << (std::ostream& os, const Cursor& c);
/// Convert a set of UUIDs into a set of cursors referencing the same \a storage.
template<typename S, typename T>
void Cursor::CursorsFromUUIDs(
S& result, StoragePtr storage, const T& uids)
......
......@@ -2,6 +2,7 @@
#define __smtk_model_CursorArrangementOps_h
#include "smtk/model/Cursor.h"
#include "smtk/model/ArrangementKind.h"
namespace smtk {
namespace model {
......@@ -157,6 +158,18 @@ public:
}
};
// -----------------------------------------------------------------------------
// What follows are methods of Cursor that require CursorArrangementOps.
// This breaks an include-dependency cycle.
template<typename T> T Cursor::instances() const
{
T result;
CursorArrangementOps::appendAllRelations(*this, INSTANCED_BY, result);
return result;
}
} // namespace model
} // namespace smtk
......
......@@ -71,7 +71,10 @@ bool EntityPhrase::buildSubphrasesInternal()
break;
}
}
if (dimBits > 0 && (dimBits > this->relatedEntity().dimensionBits() || this->relatedEntity().isModelEntity()))
if (
dimBits > 0 && this->relatedEntity().dimensionBits() > 0 && (
(dimBits > this->relatedEntity().dimensionBits() && !(dimBits & this->relatedEntity().dimensionBits())) ||
this->relatedEntity().isModelEntity()))
{
return true;
}
......@@ -79,83 +82,123 @@ bool EntityPhrase::buildSubphrasesInternal()
// This is dependent on both the entity type and the ArrangementKind
// so we cast to different cursor types and use their accessors to
// obtain lists of related entities.
{
UseEntity uent = this->m_entity.as<UseEntity>();
CellEntity cent = this->m_entity.as<CellEntity>();
ShellEntity sent = this->m_entity.as<ShellEntity>();
GroupEntity gent = this->m_entity.as<GroupEntity>();
ModelEntity ment = this->m_entity.as<ModelEntity>();
InstanceEntity ient = this->m_entity.as<InstanceEntity>();
if (uent.isValid())
{
ShellEntities boundingShells = uent.boundingShellEntities<ShellEntities>();
if (!boundingShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
boundingShells, shared_from_this()));
}
ShellEntities toplevelShells = uent.shellEntities<ShellEntities>();
if (!toplevelShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
toplevelShells, shared_from_this()));
}
}
else if (cent.isValid())
{
ShellEntities toplevelShells = cent.shellEntities();
if (!toplevelShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
toplevelShells, shared_from_this()));
}
UseEntities cellUses = cent.uses<UseEntities>();
if (!cellUses.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
cellUses, shared_from_this()));
}
Cursors inclusions = cent.inclusions<Cursors>();
if (!inclusions.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
inclusions, shared_from_this()));
}
}
else if (sent.isValid())
{
UseEntities shellUses = sent.uses<UseEntities>();
if (!shellUses.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
shellUses, shared_from_this()));
}
}
else if (gent.isValid())
{
}
else if (ment.isValid())
{
// TODO: Groups in model
// TODO: Submodels in model
CellEntities freeCellsInModel = ment.cells();
if (!freeCellsInModel.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
freeCellsInModel, shared_from_this()));
}
}
else if (ient.isValid())
{
}
}
{
UseEntity uent = this->m_entity.as<UseEntity>();
CellEntity cent = this->m_entity.as<CellEntity>();
ShellEntity sent = this->m_entity.as<ShellEntity>();
GroupEntity gent = this->m_entity.as<GroupEntity>();
ModelEntity ment = this->m_entity.as<ModelEntity>();
InstanceEntity ient = this->m_entity.as<InstanceEntity>();
if (uent.isValid())
{
CellEntity parentCell = uent.cell();
if (parentCell.isValid())
{
this->m_subphrases.push_back(
EntityPhrase::create()->setup(parentCell, shared_from_this()));
}
ShellEntities boundingShells = uent.boundingShellEntities<ShellEntities>();
if (!boundingShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
boundingShells, shared_from_this()));
}
ShellEntities toplevelShells = uent.shellEntities<ShellEntities>();
if (!toplevelShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
toplevelShells, shared_from_this()));
}
}
else if (cent.isValid())
{
ShellEntities toplevelShells = cent.shellEntities();
if (!toplevelShells.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
toplevelShells, shared_from_this()));
}
UseEntities cellUses = cent.uses<UseEntities>();
if (!cellUses.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
cellUses, shared_from_this()));
}
Cursors inclusions = cent.inclusions<Cursors>();
if (!inclusions.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
inclusions, shared_from_this()));
}
}
else if (sent.isValid())
{
UseEntities shellUses = sent.uses<UseEntities>();
if (!shellUses.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
shellUses, shared_from_this()));
}
}
else if (gent.isValid())
{
CursorArray members = gent.members<CursorArray>();
if (!members.empty())
{ // TODO: Sort by entity type, name, etc.?
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
members, shared_from_this()));
}
}
else if (ment.isValid())
{
ModelEntities freeSubmodelsInModel = ment.submodels();
if (!freeSubmodelsInModel.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
freeSubmodelsInModel, shared_from_this()));
}
GroupEntities freeGroupsInModel = ment.groups();
if (!freeGroupsInModel.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
freeGroupsInModel, shared_from_this()));
}
CellEntities freeCellsInModel = ment.cells();
if (!freeCellsInModel.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
freeCellsInModel, shared_from_this()));
}
}
else if (ient.isValid())
{
Cursor instanceOf = ient.prototype();
if (instanceOf.isValid())
{
this->m_subphrases.push_back(
EntityPhrase::create()->setup(
instanceOf, shared_from_this()));
}
}
}
// Things common to all entities
InstanceEntities instances = this->m_entity.instances<InstanceEntities>();
if (!instances.empty())
{
this->m_subphrases.push_back(
EntityListPhrase::create()->setup(
instances, shared_from_this()));
}
// III. Add attribute information
// TODO.
// IV. Add property information
......
......@@ -7,9 +7,9 @@
namespace smtk {
namespace model {
Cursor InstanceEntity::parent() const
Cursor InstanceEntity::prototype() const
{
return CursorArrangementOps::firstRelation<Cursor>(*this, EMBEDDED_IN);
return CursorArrangementOps::firstRelation<Cursor>(*this, INSTANCE_OF);
}
} // namespace model
......
......@@ -14,7 +14,7 @@ class SMTKCORE_EXPORT InstanceEntity : public Cursor
public:
SMTK_CURSOR_CLASS(InstanceEntity,Cursor,isInstanceEntity);
Cursor parent() const;
Cursor prototype() const;
// InstanceEntity& setTransform(const smtk::util::Matrix4d&);
// smtk::util::Matrix4d transform() const;
......
set(smtkModelPythonTests
modelBodyCreate
cursorTutorial
)
find_package( PythonInterp 2.7 )
......
# This Python script is part of the SMTK Cursor Tutorial.
# It should be extracted automatically from the tutorial, but isn't yet.
import sys
airfoilFile = sys.argv[1] if len(sys.argv) > 2 else 'airFoilSolidModel.json'
# --- start of tutorial ---
import smtk
from uuid import *
sm = smtk.model.Storage.create()
airfoil = sm.addGroup(smtk.model.MODEL_DOMAIN | smtk.model.DIMENSION_3, 'airfoil')
environment = sm.addGroup(smtk.model.MODEL_DOMAIN | smtk.model.DIMENSION_3, 'environment')
inlet = sm.addGroup(smtk.model.MODEL_BOUNDARY | smtk.model.DIMENSION_2, 'inlet')
skin = sm.addGroup(smtk.model.MODEL_BOUNDARY | smtk.model.DIMENSION_2, 'skin')
outlet = sm.addGroup(smtk.model.MODEL_BOUNDARY | smtk.model.DIMENSION_2, 'outlet')
mgr = smtk.attribute.Manager()
vdef = mgr.createDefinition('velocity')
for coord in ['x', 'y', 'z']:
vi = smtk.attribute.DoubleItemDefinition.New('v' + coord)
vi.setDefaultValue(-1.2 if coord == 'x' else 0.0) # in [m/s]
vdef.addItemDefinition(vi);
velocity = mgr.createAttribute('velocity', vdef)
inlet.attachAttribute(velocity.id())
print sm.entitiesOfDimension(2)
print sm.entitiesOfDimension(3)
try:
# If the file isn't present, just skip loading geometry.
jsonData = file(airFoilFile, 'r').read()
ok = smtk.model.ImportJSON.intoModel(jsonData, sm)
except:
pass
# We could select faces graphically,
# but for this example we just "know" them:
sm.addToGroup(outlet.entity(), [
UUID('12c853a5-f4d9-455d-bd61-8a73d6fe9de2'),
UUID('49a71490-5873-45a9-ab9c-e6f89f099d46'),
UUID('60fa3273-68cb-4016-94a5-c5ae632d45b8'),
UUID('892382af-532f-4dc4-bbbb-56230723503f'),
UUID('cb78cf98-b2e3-4f37-a2bf-eb823a533e5f'),
])
sm.addToGroup(inlet.entity(), [
UUID('26c312cb-f3dd-47b0-8a84-d0b186035498'),
])
sm.addToGroup(skin.entity(), [
UUID('7bc6818a-9028-4a43-b870-886d7a66793e'),
UUID('e71d4246-456d-429f-815b-074e1749f888'),
UUID('a1e7677f-40af-403b-979b-8109c730d670'),
UUID('d99a4ae1-9a60-4da7-af26-0138f4b84685'),
UUID('0bcc7039-19a5-4727-a449-7ab0af4e8ad6'),
UUID('17169461-866b-4d4f-b3b6-9ab47b271184'),
UUID('f1dcf500-571d-43ba-ba6a-581bfbb6953a'),
UUID('e98bb9e1-583d-4e3d-81d5-d9b73af1b6de'),
UUID('df663255-bd6e-40db-bd65-96be89328a61'),
UUID('bcf0ed16-3f05-4043-9313-a6a3617121fb'),
])
json = smtk.model.ExportJSON.fromModel(sm)
......@@ -8,6 +8,7 @@
#include "smtk/model/Face.h"
#include "smtk/model/FaceUse.h"
#include "smtk/model/GroupEntity.h"
#include "smtk/model/InstanceEntity.h"
#include "smtk/model/Loop.h"
#include "smtk/model/ModelEntity.h"
#include "smtk/model/Shell.h"
......@@ -977,5 +978,38 @@ ModelEntity Storage::addModel(
return ModelEntity(shared_from_this(), uid);
}
/**\brief Add an instance to storage.
*
* An instance is a reference to some other item in storage.
* Any entity may be instanced, but generally models are instanced
* as part of a scene graph.
*/
InstanceEntity Storage::addInstance()
{
smtk::util::UUID uid = this->addEntityOfTypeAndDimension(INSTANCE_ENTITY, -1);
return InstanceEntity(shared_from_this(), uid);
}
/**\brief Add an instance of the given prototype to storage.
*
* The prototype \a object (the parent of the instance)
* is a reference to some other item in storage.
* Any entity may be instanced, but generally models are instanced
* as part of a scene graph.
*/
InstanceEntity Storage::addInstance(const Cursor& object)
{
if (object.isValid())
{
smtk::util::UUID uid = this->addEntityOfTypeAndDimension(INSTANCE_ENTITY, -1);
int iidx = this->findEntity(object.entity())->findOrAppendRelation(uid);
int oidx = this->findEntity(uid)->findOrAppendRelation(object.entity());
this->arrangeEntity(uid, INSTANCE_OF, Arrangement::InstanceInstanceOfWithIndex(oidx));
this->arrangeEntity(object.entity(), INSTANCED_BY, Arrangement::InstanceInstanceOfWithIndex(iidx));
return InstanceEntity(shared_from_this(), uid);
}
return InstanceEntity();
}
} // namespace model
} //namespace smtk
......@@ -25,6 +25,7 @@ class EdgeUse;
class Face;
class FaceUse;
class GroupEntity;
class InstanceEntity;
class Loop;
class ModelEntity;
class Shell;
......@@ -126,6 +127,9 @@ public:
ModelEntity addModel(
int parametricDim = 3, int embeddingDim = 3, const std::string& name = std::string());
InstanceEntity addInstance();
InstanceEntity addInstance(const Cursor& instanceOf);
protected:
shared_ptr<UUIDsToArrangements> m_arrangements;
shared_ptr<UUIDsToTessellations> m_tessellations;
......
......@@ -34,17 +34,17 @@ Orientation UseEntity::orientation() const
this->m_entity, HAS_CELL, 0);
if (ent && arr)
{
int idx, sense;
arr->IndexAndSenseFromUseHasCell(idx, sense);
int idx, esense;
arr->IndexAndSenseFromUseHasCell(idx, esense);
smtk::util::UUID cellId = ent->relations()[idx];
// Now find the cell's HAS_USE record with the same sense as us:
int arrIdx = this->m_storage->findCellHasUseWithSense(cellId, sense);
int arrIdx = this->m_storage->findCellHasUseWithSense(cellId, esense);
if (arrIdx >= 0)
{
// Now find the orientation of that use of the cell:
Orientation orient;
this->m_storage->findArrangement(cellId, HAS_USE, arrIdx)
->IndexSenseAndOrientationFromCellHasUse(idx, sense, orient);
->IndexSenseAndOrientationFromCellHasUse(idx, esense, orient);