Commit fcfd9678 authored by David Thompson's avatar David Thompson
Browse files

WIP: Progress on writing a resource.

Domains and nodes are not yet properly serialized,
but a basic JSON object is written that includes the
SMTK string manager state.

This commit also tracks the change in SMTK that passes
a Managers instance to read/write/create methods (and
to operations).
parent 72dbc071
......@@ -2,6 +2,9 @@ set(sources)
set(headers
queries/SelectionFootprint.h
)
set(operations
Write
)
list(APPEND classes
Resource
......@@ -46,11 +49,28 @@ list(APPEND classes
Landmark
detail/NodeContainer
json/Helper
json/jsonResource
json/jsonComponent
json/jsonDomain
json/jsonDomainMap
# arcs/Children<NodeType, bool Hold>
# arcs/Parents<NodeType>
# arcs/DerivedData
)
# NB: Keep the next two foreach loops in order!
# Encode operation SBT files into headers and operations into classes.
foreach(operation ${operations})
list(APPEND classes "operators/${operation}")
smtk_encode_file(
"${CMAKE_CURRENT_SOURCE_DIR}/operators/${operation}.sbt"
TARGET_OUTPUT targetName
)
list(APPEND markupDependencies ${targetName})
endforeach()
# Turn "classes" into source and headers entries
foreach(class ${classes})
list(APPEND headers ${class}.h)
......@@ -59,7 +79,7 @@ endforeach()
add_library(smtkMarkup SHARED ${sources} ${headers})
smtk_export_header(smtkMarkup Exports.h)
# add_dependencies(smtkMarkup ${aevaDependencies})
add_dependencies(smtkMarkup ${markupDependencies})
target_link_libraries(smtkMarkup
PUBLIC
smtkCore
......
......@@ -8,6 +8,8 @@
#include "smtk/markup/ArcEditor.h"
#include "nlohmann/json.hpp"
namespace smtk {namespace markup { class Group; } }
namespace smtk {namespace markup { class Label; } }
......@@ -30,6 +32,17 @@ public:
{
}
template<typename... Args>
Component(const nlohmann::json* j, Args&&... args)
: smtk::graph::Component(std::forward<Args>(args)...)
{
auto it = j->find("name");
if (it != j->end())
{
m_name = it->get<std::string>();
}
}
~Component() override;
/// The index is a compile-time intrinsic of the derived resource; as such, it cannot be set.
......
......@@ -42,5 +42,15 @@ std::shared_ptr<Domain> DomainMap::operator [] (const smtk::string::Token& space
return this->find(space);
}
std::unordered_set<smtk::string::Token> DomainMap::keys() const
{
std::unordered_set<smtk::string::Token> result;
for (const auto& entry : m_domains)
{
result.insert(entry.first);
}
return result;
}
} // namespace markup
} // namespace smtk
......@@ -7,6 +7,7 @@
#include <memory>
#include <unordered_map>
#include <unordered_set>
namespace smtk
{
......@@ -55,6 +56,9 @@ public:
return this->insert(space, domain);
}
/// Return a set of all the domain "names" in the map.
std::unordered_set<smtk::string::Token> keys() const;
protected:
std::unordered_map<smtk::string::Token, std::shared_ptr<Domain>> m_domains;
};
......
......@@ -21,32 +21,19 @@ namespace
using QueryTypes = std::tuple<SelectionFootprint>;
}
NodeFactory Resource::s_nodeFactory;
DomainFactory Resource::s_domainFactory;
Resource::Resource(const smtk::common::UUID& uid, smtk::resource::ManagerPtr manager)
: Superclass(uid, manager)
{
this->queries().registerQueries<QueryTypes>();
// Discrete models have ID namespaces for points and cells.
m_domains.insert("points", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("cells", std::make_shared<smtk::markup::IdSpace>());
// Side sets of discrete models also require an ID namespace and map
// for moving between a "side ID" and a boundary of the reference element
// (note that sides may be of any dimension lower than the cell, not just
// a single dimension lower).
// We provide an IdSpace for each cell shape VTK supports.
m_domains.insert("sides(hexahedron)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(tetrahedron)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(wedge)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(pyramid)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(quadrilateral)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(triangle)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(line)", std::make_shared<smtk::markup::IdSpace>());
m_domains.insert("sides(vertex)", std::make_shared<smtk::markup::IdSpace>());
this->initialize();
}
Resource::Resource(smtk::resource::ManagerPtr manager)
: Superclass(manager)
{
this->queries().registerQueries<QueryTypes>();
this->initialize();
}
std::function<bool(const smtk::resource::Component&)> Resource::queryOperation(
......@@ -65,5 +52,32 @@ std::function<bool(const smtk::resource::Component&)> Resource::queryOperation(
return functor;
}
void Resource::initialize()
{
this->queries().registerQueries<QueryTypes>();
std::vector<std::shared_ptr<smtk::markup::IdSpace>> domains{
// Discrete models have ID namespaces for points and cells.
std::make_shared<smtk::markup::IdSpace>("points"),
std::make_shared<smtk::markup::IdSpace>("cells"),
// Side sets of discrete models also require an ID namespace and map
// for moving between a "side ID" and a boundary of the reference element
// (note that sides may be of any dimension lower than the cell, not just
// a single dimension lower).
// We provide an IdSpace for each cell shape VTK supports.
std::make_shared<smtk::markup::IdSpace>("sides(hexahedron)"),
std::make_shared<smtk::markup::IdSpace>("sides(tetrahedron)"),
std::make_shared<smtk::markup::IdSpace>("sides(wedge)"),
std::make_shared<smtk::markup::IdSpace>("sides(pyramid)"),
std::make_shared<smtk::markup::IdSpace>("sides(quadrilateral)"),
std::make_shared<smtk::markup::IdSpace>("sides(triangle)"),
std::make_shared<smtk::markup::IdSpace>("sides(line)"),
std::make_shared<smtk::markup::IdSpace>("sides(vertex)")
};
for (const auto& domain : domains)
{
m_domains.insert(domain->name(), domain);
}
}
} // namespace markup
} // namespace smtk
......@@ -6,7 +6,10 @@
#include "smtk/graph/Resource.h"
#include "smtk/resource/DerivedFrom.h"
#include "smtk/resource/Manager.h"
#include "smtk/markup/Domain.h"
#include "smtk/markup/DomainFactory.h"
#include "smtk/markup/DomainMap.h"
#include "smtk/markup/NodeFactory.h"
#include "smtk/markup/Traits.h"
#include "smtk/markup/Exports.h"
......@@ -45,7 +48,7 @@ public:
Resource(const Resource&) = delete;
virtual ~Resource() = default;
// Wrap to avoid name conflict in MSVC.
// Wrap this method (instead of create()) to avoid name conflict in MSVC.
template <typename componentT>
smtk::shared_ptr<componentT> createNode()
{
......@@ -62,16 +65,32 @@ public:
DomainMap& domains() { return m_domains; }
const DomainMap& domains() const { return m_domains; }
/**\brief Return the factory used to construct markup nodes.
*
* This factory is used to deserialize components from json objects.
*/
static NodeFactory& nodeFactory() { return s_nodeFactory; }
/**\brief Return the factory used to construct markup domains.
*
* This factory is used to deserialize components from json objects.
*/
static DomainFactory& domainFactory() { return s_domainFactory; }
protected:
friend class Component;
Resource(const smtk::common::UUID&, smtk::resource::Manager::Ptr manager = nullptr);
Resource(smtk::resource::Manager::Ptr manager = nullptr);
friend class Component;
DomainMap m_domains;
void initialize(); // Initialization common to all constructors.
template<typename Modifier>
bool modifyComponent(Component& component, const Modifier& modifier);
DomainMap m_domains;
static NodeFactory s_nodeFactory;
static DomainFactory s_domainFactory;
};
template<typename Modifier>
......
......@@ -64,7 +64,6 @@ struct SMTKMARKUP_EXPORT Traits
using NodeTypes = std::tuple<
AnalyticShape,
AssignedIds,
BoundaryOperator,
Box,
Collection,
Comment,
......@@ -80,16 +79,13 @@ struct SMTKMARKUP_EXPORT Traits
Grid,
Group,
IdAllotment,
IdSpace,
Image,
ImplicitShape,
Index,
Label,
LabelMap,
Landmark,
Ontology,
OntologyIdentifier,
ParameterSpace,
Plane,
RangedSubset,
References,
......@@ -100,9 +96,9 @@ struct SMTKMARKUP_EXPORT Traits
Subset,
SurfaceGrid,
VolumeGrid
>;
>;
using ArcTypes = std::tuple<
>;
>;
/*
typedef std::tuple<ChildrenAs<CompSolid>, ChildrenAs<Solid>, ChildrenAs<Shell>, ChildrenAs<Face>,
ChildrenAs<Wire>, ChildrenAs<Edge>, ChildrenAs<Vertex>, Children, ParentsAs<Compound>,
......@@ -111,6 +107,12 @@ struct SMTKMARKUP_EXPORT Traits
ArcTypes;
*/
using NodeContainer = detail::NodeContainer;
using DomainTypes = std::tuple<
BoundaryOperator,
IdSpace,
Index,
ParameterSpace
>;
};
}
}
......
// Copyright © Kitware Inc under the [BSD-3-clause license](https://opensource.org/licenses/BSD-3-Clause).
#include "smtk/markup/json/Helper.h"
#include "smtk/io/Logger.h"
#include <thread>
#include <vector>
namespace
{
thread_local std::vector<std::unique_ptr<smtk::markup::json::Helper>> g_instanceStack;
} // anonymous namespace
namespace smtk
{
namespace markup
{
namespace json
{
Helper::Helper() = default;
Helper::~Helper() = default;
Helper& Helper::instance()
{
if (g_instanceStack.empty())
{
g_instanceStack.emplace_back(new Helper);
}
return *(g_instanceStack.back());
}
Helper& Helper::pushInstance(const std::shared_ptr<smtk::markup::Resource>& parent)
{
std::shared_ptr<smtk::common::Managers> managers;
if (!g_instanceStack.empty())
{
managers = g_instanceStack.back()->managers();
}
g_instanceStack.emplace_back(new Helper);
g_instanceStack.back()->setManagers(managers);
g_instanceStack.back()->m_resource = parent;
g_instanceStack.back()->m_topLevel = false;
return *(g_instanceStack.back());
}
void Helper::popInstance()
{
if (!g_instanceStack.empty())
{
g_instanceStack.pop_back();
}
}
std::size_t Helper::nestingDepth()
{
return g_instanceStack.size();
}
void Helper::setManagers(const smtk::common::Managers::Ptr& managers)
{
m_managers = managers;
}
smtk::common::Managers::Ptr Helper::managers()
{
return m_managers;
}
std::shared_ptr<smtk::markup::Resource> Helper::resource() const
{
return m_resource.lock();
}
void Helper::clear()
{
}
} // namespace json
} // namespace markup
} // namespace smtk
// Copyright © Kitware Inc under the [BSD-3-clause license](https://opensource.org/licenses/BSD-3-Clause).
#ifndef smtk_markup_json_Helper_h
#define smtk_markup_json_Helper_h
#include "smtk/markup/Resource.h"
#include "smtk/common/Managers.h"
#include "smtk/common/TypeName.h"
#include <string>
namespace smtk
{
namespace markup
{
namespace json
{
/**\brief A helper for serialization of markup resources.
*
* This is needed in order for components to be deserialized
* as they cannot be constructed without access to the resource
* which will own them (and which cannot be provided to them
* through the from_json method).
*
* It is also used to provide access to application data
* through the smtk::common::Managers::Ptr it can hold.
*/
class SMTKCORE_EXPORT Helper
{
public:
/// JSON data type
using json = nlohmann::json;
/// Destructor is public, but you shouldn't use it.
~Helper();
/// Return the helper "singleton".
///
/// The object returned is a per-thread instance
/// at the top of a stack that may be altered using
/// the pushInstance() and popInstance() methods.
/// This allows nested deserializers to each have
/// their own context that appears to be globally
/// available.
static Helper& instance();
/// Push a new helper instance on the local thread's stack.
///
/// The returned \a Helper will have:
/// + The same managers as the previous (if any) helper.
/// + The \a parent markup is assigned the ID 0.
static Helper& pushInstance(const std::shared_ptr<smtk::markup::Resource>& resource);
/// Pop a helper instance off the local thread's stack.
static void popInstance();
/// Return the nesting level (i.e., the number of helper instances in the stack).
///
/// The outermost helper will return 1 (assuming you have called instance() first).
static std::size_t nestingDepth();
/// Set/get the managers to use when serializing/deserializing.
///
/// Call setManagers() with an instance of all your application's
/// managers before attempting to serialize/deserialize as helpers
/// are allowed to use managers as needed.
void setManagers(const smtk::common::Managers::Ptr& managers);
smtk::common::Managers::Ptr managers();
/// Return the current resource being (de)serialized.
std::shared_ptr<smtk::markup::Resource> resource() const;
/// Reset the helper's state.
///
/// This should be called before beginning serialization or deserialization.
/// Additionally, calling it after each of these tasks is recommended since
/// it will free memory.
void clear();
protected:
Helper();
std::weak_ptr<smtk::markup::Resource> m_resource;
smtk::common::Managers::Ptr m_managers;
/// m_topLevel indicates whether pushInstance() (false) or instance() (true)
/// was used to create this helper.
bool m_topLevel = true;
};
} // namespace json
} // namespace markup
} // namespace smtk
#endif // smtk_markup_json_Helper_h
#include "smtk/markup/json/jsonComponent.h"
#include "smtk/markup/json/Helper.h"
namespace smtk
{
namespace markup
{
void to_json(nlohmann::json& j, const smtk::markup::Component::Ptr& component)
{
if (!component)
{
return;
}
j["type"] = component->typeName();
j["name"] = component->name();
j["id"] = component->id();
}
void from_json(const nlohmann::json& j, smtk::markup::Component::Ptr& component)
{
auto& helper = json::Helper::instance();
auto typeName = j.at("type").get<std::string>();
auto name = j.at("name").get<std::string>();
auto uid = j.at("id").get<smtk::common::UUID>();
component = Resource::nodeFactory().makeFromName(typeName, &j, helper.resource(), uid);
}
} // namespace markup
} // namespace smtk
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_markup_json_jsonComponent_h
#define smtk_markup_json_jsonComponent_h
#include "smtk/markup/Exports.h"
#include "smtk/markup/Component.h"
#include "nlohmann/json.hpp"
namespace smtk
{
namespace markup
{
SMTKMARKUP_EXPORT void to_json(nlohmann::json& j, const smtk::markup::Component::Ptr& component);
SMTKMARKUP_EXPORT void from_json(const nlohmann::json& j, smtk::markup::Component::Ptr& component);
} // namespace markup
} // namespace smtk
#endif // smtk_markup_json_jsonComponent_h
#include "smtk/markup/json/jsonDomain.h"
#include "smtk/string/json/jsonToken.h"
namespace smtk
{
namespace markup
{
void to_json(nlohmann::json& j, const std::shared_ptr<smtk::markup::Domain>& domain)
{
if (!domain)
{
return;
}
j["name"] = domain->name();
// TODO: dispatch based on subclass. See smtk/task/json/jsonTask for one approach.
}
void from_json(const nlohmann::json& j, std::shared_ptr<smtk::markup::Domain>& domain)
{
// TODO
#if 0
auto& helper = json::Helper::instance();
auto typeName = j.at("type").get<std::string>();
auto name = j.at("name").get<std::string>();
auto uid = j.at("id").get<smtk::common::UUID>();
component = Resource::nodeFactory().makeFromName(typeName, &j, helper.resource(), uid);
#endif
}
} // namespace markup
} // namespace smtk
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_markup_json_jsonDomain_h
#define smtk_markup_json_jsonDomain_h
#include "smtk/markup/Exports.h"
#include "smtk/markup/Domain.h"
#include "nlohmann/json.hpp"
#include <memory>
namespace smtk
{
namespace markup
{
SMTKMARKUP_EXPORT void to_json(nlohmann::json& j, const std::shared_ptr<smtk::markup::Domain>& domain);
SMTKMARKUP_EXPORT void from_json(const nlohmann::json& j, std::shared_ptr<smtk::markup::Domain>& domain);
} // namespace markup
} // namespace smtk
#endif // smtk_markup_json_jsonDomain_h
#include "smtk/markup/json/jsonDomainMap.h"
#include "smtk/markup/json/jsonDomain.h"
namespace smtk
{
namespace markup
{
void to_json(nlohmann::json& j, const smtk::markup::DomainMap& domainMap)
{
j = nlohmann::json::array();
for (const auto& key : domainMap.keys())
{
nlohmann::json jdomain = domainMap[key];
j.push_back(jdomain);
}
}
void from_json(const nlohmann::json& j, smtk::markup::DomainMap& domainMap)
{
// TODO