Geometry library

As part of our Planning for SMTK v3.1 and v4.0 discussion, we mentioned the possibility of separating tessellation information into another library (the bullet named “Geometry library” in the list of SMTK 3.1. features). This page discusses design(s) for that change.

Variant 1

We could have smtk::model::Resource (and other resources if the base functionality is added to smtk::resource::Resource as shown below) provide a mechanism to “attach” things to components much like resource Links. In addition to model tessellation information, we could use the same technique to supply the integer, floating-point, and string properties that are currently implemented only for model resources.

First, we can define a base class with virtual methods for querying a map:

namespace smtk {
namespace resource {

class PropertyMap
{
  /// Return true if the property exists on \a obj (or \a uid).
  bool has(const smtk::resource::PersistentObjectPtr& obj) const;
  bool has(const smtk::common::UUID& uid) const;
  /// Erase any property on the given object or UUID, returning true on success.
  bool erase(const smtk::common::UUID& uid);
  bool erase(const smtk::resource::PersistentObjectPtr& uid);
  /// Remove all entries in the map. Returns the number of items erased.
  size_t clear();

  /// Reset the property.
  ///
  /// This is by default equivalent to erasing the property, but some properties
  /// may be generated via examination of an object (perhaps in combination with
  /// application context). Subclasses of PropertyMap for those properties may
  /// override these methods, allowing the properties to be contextually regenerated.
  virtual bool reset(const smtk::resource::PersistentObjectPtr& obj)
  { return this->erase(obj); }
  virtual bool reset(const smtk::common::UUID& uid)
  { return this->erase(uid); }
};

using PropertyMapPtr = std::shared_ptr<PropertyMap>;

Since the maps store different types of values on keys that are always UUIDs or persistent-object pointers, each type of map would require a subclass. Below is an example for string properties:

class StringPropertyMap : public PropertyMap
{
public:
  using StringVector = std::vector<std::string>;
  using ConstStringVector = const std::vector<std::string>;

  StringVector find(const smtk::resource::PersistentObjectPtr& obj) const;
  StringVector& findOrAdd(const smtk::resource::PersistentObjectPtr& obj);

  bool setValue(const smtk::resource::PersistentObjectPtr& obj, const StringVector& value);

protected:
  std::map<smtk::resource::PersistentObjectPtr, StringVector> m_data;
}

Resources would keep a map of PropertyMap instances around, with some predefined keys owned by SMTK. Positive key values would be available for applications to use.

class Resource
{
  using PropertyIndex = int;
  constexpr PropertyIndex StringProperties = -37;
  constexpr PropertyIndex DoubleProperties = -39;
  constexpr PropertyIndex IntProperties = -41;

  StringPropertyMap::ConstPtr stringProperties() const
  { return propertyAs<StringPropertyMap>(StringProperties); }
  StringPropertyMap::Ptr stringProperties()
  { return propertyAs<StringPropertyMap>(StringProperties); }

  template<typename PropertyType>
  typename T::ConstPtr propertyAs(PropertyIndex idx) const
  { return std::dynamic_pointer_cast<const PropertyType>(m_propertyMaps[idx]); }

  template<typename PropertyType>
  typename T::Ptr propertyAs(PropertyIndex idx)
  { return std::dynamic_pointer_cast<PropertyType>(m_propertyMaps[idx]); }

protected:
  std::map<PropertyIndex, PropertyMapPtr> m_propertyMaps;
};

} // namespace resource

Finally, for visualization information, the model resource could provide a reserved key. However, it would not necessarily provide a method like visualProperties() since the return type would require linking to VTK or VTK-m:

namespace model {

class Resource : public DerivedFrom<smtk::resource::Resource>
{
public:
  constexpr PropertyIndex VisualProperties = -42;
};

}
}

Then, in a separate library, we can declare

namespace smtk {
namespace model {

class VisualPropertyMap : public PropertyMap
{
public:
  using Data = vtkDataObject*;
  using ConstData = const vtkDataObject*;

  ConstData find(const smtk::resource::PersistentObjectPtr& obj) const;
  Data& findOrAdd(const smtk::resource::PersistentObjectPtr& obj);

  bool setValue(const smtk::resource::PersistentObjectPtr& obj, const Data& data);

  /// Return the bounding box of obj (or an invalid one if none exists):
  std::array<double, 6> boundingBox(const smtk::resource::PersistentObjectPtr& obj);
};

}
}

By using the templated method on the base resource class it would be possible to fetch the map of tessellation information, query it for matches, erase entries, or even regenerate entries (say due to a modified entity) without requiring the code to be directly linked to VTK. If linking to VTK is feasible, then actual tessellation data could be accessed directly.

We might go further, though, and allow code not linked to VTK to invoke methods from a library that is linked to VTK in order to update tessellations. For instance, we could make VisualPropertyMap have a base class independent of VTK that tracked generation numbers for visual properties and use smtk::common::Extension to request any available providers update actual data. The model resource could provide access to the base class. The base class might provide methods to access bounding box information if available.

Other Variants

The above is not intended to be the only option, just one. This page is a wiki so anyone with an account can suggest other variants by adding them here. If you have comments on existing variants, please add them by replying below.