From 8a214bb69634f51cc3db7ed64c78609d6051ad8f Mon Sep 17 00:00:00 2001 From: Paul Gessinger <paul.gessinger@cern.ch> Date: Mon, 12 Feb 2018 13:05:08 +0100 Subject: [PATCH] add facility to produce PlaneSurfaces from variant_data --- .../include/ACTS/Surfaces/RectangleBounds.hpp | 2 + Core/include/ACTS/Surfaces/TriangleBounds.hpp | 2 + .../ACTS/Utilities/InstanceFactory.hpp | 52 ++++++ Core/include/ACTS/Utilities/VariantData.hpp | 156 ++++++++++++++++-- Core/src/Surfaces/PlaneSurface.cpp | 36 +++- Core/src/Surfaces/RectangleBounds.cpp | 14 ++ Core/src/Surfaces/TriangleBounds.cpp | 24 +++ Tests/Surfaces/PlaneSurfaceTests.cpp | 20 ++- 8 files changed, 283 insertions(+), 23 deletions(-) create mode 100644 Core/include/ACTS/Utilities/InstanceFactory.hpp diff --git a/Core/include/ACTS/Surfaces/RectangleBounds.hpp b/Core/include/ACTS/Surfaces/RectangleBounds.hpp index ddbb41470..43af5380a 100644 --- a/Core/include/ACTS/Surfaces/RectangleBounds.hpp +++ b/Core/include/ACTS/Surfaces/RectangleBounds.hpp @@ -44,6 +44,8 @@ public: /// @param halfY halflength in Y RectangleBounds(double halfX, double halfY); + RectangleBounds(const variant_data& data); + virtual ~RectangleBounds(); virtual RectangleBounds* diff --git a/Core/include/ACTS/Surfaces/TriangleBounds.hpp b/Core/include/ACTS/Surfaces/TriangleBounds.hpp index d86f29913..5fc123ae8 100644 --- a/Core/include/ACTS/Surfaces/TriangleBounds.hpp +++ b/Core/include/ACTS/Surfaces/TriangleBounds.hpp @@ -51,6 +51,8 @@ public: /// @param vertices is the vector of vertices TriangleBounds(const std::array<Vector2D, 3>& vertices); + TriangleBounds(const variant_data &data); + virtual ~TriangleBounds(); virtual TriangleBounds* diff --git a/Core/include/ACTS/Utilities/InstanceFactory.hpp b/Core/include/ACTS/Utilities/InstanceFactory.hpp new file mode 100644 index 000000000..26ea38f76 --- /dev/null +++ b/Core/include/ACTS/Utilities/InstanceFactory.hpp @@ -0,0 +1,52 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2018 ACTS project team +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef ACTS_PLUGINS_JSONPLUGIN_INSTANCEFACTORY_H +#define ACTS_PLUGINS_JSONPLUGIN_INSTANCEFACTORY_H 1 + +#include <boost/functional/value_factory.hpp> +#include <map> +#include "ACTS/Utilities/VariantData.hpp" +#include "ACTS/Utilities/ThrowAssert.hpp" + +#include "ACTS/Surfaces/RectangleBounds.hpp" +#include "ACTS/Surfaces/TriangleBounds.hpp" + +namespace Acts { + +using PlanarBoundsPtr = std::shared_ptr<const PlanarBounds>; +using PlanarBoundsFactory = std::function<PlanarBoundsPtr(const variant_data&)>; + +class InstanceFactory +{ +public: + InstanceFactory() + { + // set up map to store factories + m_planarBounds["RectangleBounds"] = [](auto const& data) { + return std::make_shared<const RectangleBounds>(data); + }; + m_planarBounds["TriangleBounds"] = [](auto const& data) { + return std::make_shared<const TriangleBounds>(data); + }; + } + + PlanarBoundsPtr + planarBounds(const std::string& cname, const variant_data& data) + { + throw_assert(m_planarBounds.count(cname), "No factory found for class "+cname); + return m_planarBounds.at(cname)(data); + } + +private: + std::map<std::string, PlanarBoundsFactory> m_planarBounds; +}; + +} // namespace Acts + +#endif diff --git a/Core/include/ACTS/Utilities/VariantData.hpp b/Core/include/ACTS/Utilities/VariantData.hpp index 3d8adec48..9b9f86a65 100644 --- a/Core/include/ACTS/Utilities/VariantData.hpp +++ b/Core/include/ACTS/Utilities/VariantData.hpp @@ -17,6 +17,7 @@ #include <vector> #include "ACTS/Utilities/Definitions.hpp" +#include "ACTS/Utilities/ThrowAssert.hpp" namespace Acts { @@ -35,11 +36,11 @@ class variant_map; class variant_vector; using variant_data = boost::variant<int, - double, - std::string, - bool, - boost::recursive_wrapper<variant_map>, - boost::recursive_wrapper<variant_vector>>; + double, + std::string, + bool, + boost::recursive_wrapper<variant_map>, + boost::recursive_wrapper<variant_vector>>; class variant_map { @@ -63,6 +64,20 @@ public: return m_map.count(key); } + template <class T> + T& + get(const std::string& key) + { + return boost::get<T>(m_map.at(key)); + } + + template <class T> + const T& + get(const std::string& key) const + { + return boost::get<T>(m_map.at(key)); + } + iterator begin() { @@ -110,10 +125,31 @@ public: return m_vector.at(idx); } + const variant_data& + at(size_t idx) const + { + return m_vector.at(idx); + } + void - push_back(variant_data&& data) { + push_back(variant_data&& data) + { m_vector.push_back(data); } + + template <class T> + T& + get(const size_t& idx) + { + return boost::get<T>(m_vector.at(idx)); + } + + template <class T> + const T& + get(const size_t& idx) const + { + return boost::get<T>(m_vector.at(idx)); + } iterator begin() @@ -140,7 +176,6 @@ private: vector_t m_vector; }; - class variant_json_visitor : public boost::static_visitor<> { public: @@ -248,8 +283,7 @@ private: } }; -inline -std::string +inline std::string to_json(const variant_data& data, bool pretty = false) { variant_json_visitor jv(pretty); @@ -257,24 +291,116 @@ to_json(const variant_data& data, bool pretty = false) return jv.str(); } -inline -std::ostream& +inline std::ostream& operator<<(std::ostream& os, const variant_data& data) { os << to_json(data, true) << std::endl; return os; } -inline -variant_map -to_variant(const Vector2D &vec) { +inline variant_map +to_variant(const Vector2D& vec) +{ using namespace std::string_literals; variant_map data; - data["type"] = "Vector2D"s; + data["type"] = "Vector2D"s; data["payload"] = variant_vector({vec[0], vec[1]}); return data; } +inline variant_map +to_variant(const Transform3D& trf) +{ + using namespace std::string_literals; + variant_map data; + data["type"] = "Transform3D"s; + + variant_map payload; + // payload["matrix"] = to_variant(trf.matrix()); + variant_vector matrix_data; + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + matrix_data.push_back(trf(i, j)); + } + } + payload["data"] = matrix_data; + + data["payload"] = payload; + return data; +} + +inline variant_map +to_variant(const ActsMatrixD<4, 4>& matrix) +{ + using namespace std::string_literals; + variant_map data; + data["type"] = "Matrix4x4"s; + + variant_map payload; + payload["cols"] = 4; + payload["rows"] = 4; + + variant_vector matrix_data; + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + matrix_data.push_back(matrix(i, j)); + } + } + payload["data"] = matrix_data; + + data["payload"] = payload; + + return data; +} + +template<typename T> +inline T +from_variant(const variant_data& data_); + +template<> +inline Transform3D +from_variant<Transform3D>(const variant_data& data_) +{ + throw_assert(data_.which() == 4, "Must be variant_map"); + const variant_map& data = boost::get<variant_map>(data_); + throw_assert(data.get<std::string>("type") == "Transform3D", + "Must be type Transform3D"); + + const variant_map &payload = data.get<variant_map>("payload"); + + const variant_vector &matrix_data = payload.get<variant_vector>("data"); + Transform3D trf; + for(size_t i=0;i<4;i++) { + for(size_t j=0;j<4;j++) { + + size_t k = i*4+j; + double value = matrix_data.get<double>(k); + trf(i, j) = value; + } + } + + return trf; +} + +template<> +inline Vector2D +from_variant<Vector2D>(const variant_data& data_) +{ + throw_assert(data_.which() == 4, "Must be variant_map"); + const variant_map& data = boost::get<variant_map>(data_); + throw_assert(data.get<std::string>("type") == "Vector2D", + "Must be type Vector2D"); + + const variant_vector &vector_data = data.get<variant_vector>("payload"); + + Vector2D vec; + for(size_t i=0;i<2;i++) { + vec[i] = vector_data.get<double>(i); + } + + return vec; +} + /*int main() { diff --git a/Core/src/Surfaces/PlaneSurface.cpp b/Core/src/Surfaces/PlaneSurface.cpp index e0910140f..1484895e3 100644 --- a/Core/src/Surfaces/PlaneSurface.cpp +++ b/Core/src/Surfaces/PlaneSurface.cpp @@ -19,8 +19,10 @@ #include "ACTS/Surfaces/InfiniteBounds.hpp" #include "ACTS/Surfaces/RectangleBounds.hpp" #include "ACTS/Utilities/Identifier.hpp" -#include "ACTS/Utilities/VariantData.hpp" #include "ACTS/Utilities/ThrowAssert.hpp" +#include "ACTS/Utilities/VariantData.hpp" + +#include "ACTS/Utilities/InstanceFactory.hpp" Acts::PlaneSurface::PlaneSurface(const PlaneSurface& other) : GeometryObject(), Surface(other), m_bounds(other.m_bounds) @@ -74,12 +76,30 @@ Acts::PlaneSurface::PlaneSurface(std::shared_ptr<const Transform3D> htrans, Acts::PlaneSurface::PlaneSurface(const variant_data& data_) { // we need to figure out which way the PS was constructed before - throw_assert(data_.which() == 5, "Variant data must be map"); + throw_assert(data_.which() == 4, "Variant data must be map"); variant_map data = boost::get<variant_map>(data_); - throw_assert(data.count("type") && data["type"] == "PlaneSurface", - "Variant data must have type and type must be PlaneSurface"); - - std::cout << "go unpack" << std::endl; + throw_assert(data.count("type"), "Variant data must have type."); + // std::string type = boost::get<std::string>(data["type"]); + std::string type = data.get<std::string>("type"); + throw_assert(type == "PlaneSurface", + "Variant data type must be PlaneSurface"); + + variant_map payload = data.get<variant_map>("payload"); + variant_map bounds = payload.get<variant_map>("bounds"); + std::string boundsType = bounds.get<std::string>("type"); + + InstanceFactory factory; + std::shared_ptr<const PlanarBounds> pbounds + = factory.planarBounds(boundsType, bounds); + + m_bounds = pbounds; + + if (payload.count("transform")) { + // we have a transform + auto trf = std::make_shared<const Transform3D>( + from_variant<Transform3D>(payload.get<variant_map>("transform"))); + m_transform = trf; + } } Acts::PlaneSurface::~PlaneSurface() {} @@ -187,6 +207,10 @@ Acts::PlaneSurface::toVariantData() const variant_data bounds = m_bounds->toVariantData(); payload["bounds"] = bounds; + if (m_transform) { + payload["transform"] = to_variant(*m_transform); + } + variant_map data; data["type"] = "PlaneSurface"s; data["payload"] = payload; diff --git a/Core/src/Surfaces/RectangleBounds.cpp b/Core/src/Surfaces/RectangleBounds.cpp index eb25fdd13..b2df2556a 100644 --- a/Core/src/Surfaces/RectangleBounds.cpp +++ b/Core/src/Surfaces/RectangleBounds.cpp @@ -12,6 +12,7 @@ #include "ACTS/Surfaces/RectangleBounds.hpp" #include "ACTS/Utilities/VariantData.hpp" +#include "ACTS/Utilities/ThrowAssert.hpp" #include <cmath> #include <iomanip> @@ -22,6 +23,19 @@ Acts::RectangleBounds::RectangleBounds(double halex, double haley) { } +Acts::RectangleBounds::RectangleBounds(const variant_data& data_) +{ + throw_assert(data_.which() == 4, "Variant data must be map"); + const variant_map &data = boost::get<variant_map>(data_); + std::string type = data.get<std::string>("type"); + throw_assert(type == "RectangleBounds", "Type must be RectangleBounds"); + + const variant_map &payload = data.get<variant_map>("payload"); + + m_halfX = payload.get<double>("halflengthX"); + m_halfY = payload.get<double>("halflengthY"); +} + Acts::RectangleBounds::~RectangleBounds() { } diff --git a/Core/src/Surfaces/TriangleBounds.cpp b/Core/src/Surfaces/TriangleBounds.cpp index c705def38..48e9fe4d9 100644 --- a/Core/src/Surfaces/TriangleBounds.cpp +++ b/Core/src/Surfaces/TriangleBounds.cpp @@ -28,6 +28,30 @@ Acts::TriangleBounds::TriangleBounds(const std::array<Vector2D, 3>& vertices) m_boundingBox = RectangleBounds(mx, my); } +Acts::TriangleBounds::TriangleBounds(const variant_data& data_) + : m_vertices(), m_boundingBox(0, 0) +{ + throw_assert(data_.which() == 4, "Variant data must be map"); + const variant_map &data = boost::get<variant_map>(data_); + std::string type = data.get<std::string>("type"); + throw_assert(type == "TriangleBounds", "Type must be TriangleBounds"); + + const variant_map &payload = data.get<variant_map>("payload"); + const variant_vector &vertices = payload.get<variant_vector>("vertices"); + throw_assert(vertices.size() == 3, "Vertices for triangle must be exactly 3."); + + double mx = 0, my = 0; + for(size_t i=0;i<3;i++) { + Vector2D vtx = from_variant<Vector2D>(vertices.at(i)); + mx = std::max(mx, std::abs(vtx.x())); + my = std::max(my, std::abs(vtx.y())); + m_vertices.at(i) = vtx; + } + + m_boundingBox = RectangleBounds(mx, my); +} + + Acts::TriangleBounds::~TriangleBounds() { } diff --git a/Tests/Surfaces/PlaneSurfaceTests.cpp b/Tests/Surfaces/PlaneSurfaceTests.cpp index d1effa22e..b31ce94f7 100644 --- a/Tests/Surfaces/PlaneSurfaceTests.cpp +++ b/Tests/Surfaces/PlaneSurfaceTests.cpp @@ -201,20 +201,36 @@ namespace Test { // build auto rectBounds = std::make_shared<const RectangleBounds>(5, 10); auto idTrf = std::make_shared<const Transform3D>(Transform3D::Identity()); - PlaneSurface rectSrf(idTrf, rectBounds); + auto rot = std::make_shared<const Transform3D>(AngleAxis3D(M_PI/4., Vector3D::UnitZ())); + PlaneSurface rectSrf(rot, rectBounds); variant_data rectVariant = rectSrf.toVariantData(); std::cout << rectVariant << std::endl; // rebuild from variant PlaneSurface rectSrfRec(rectVariant); + auto rectBoundsRec = dynamic_cast<const RectangleBounds*>(&rectSrfRec.bounds()); + BOOST_CHECK_CLOSE(rectBounds->halflengthX(), rectBoundsRec->halflengthX(), 1e-4); + BOOST_CHECK_CLOSE(rectBounds->halflengthY(), rectBoundsRec->halflengthY(), 1e-4); + BOOST_TEST(rot->isApprox(rectSrfRec.transform(), 1e-4)); std::array<Vector2D, 3> vertices = {{Vector2D(1,1), Vector2D(1, -1), Vector2D(-1, 1)}}; auto triangleBounds = std::make_shared<const TriangleBounds>(vertices); - PlaneSurface triangleSrf(idTrf, triangleBounds); + PlaneSurface triangleSrf(rot, triangleBounds); variant_data triangleVariant = triangleSrf.toVariantData(); std::cout << triangleVariant << std::endl; + // rebuild + PlaneSurface triangleSrfRec(triangleVariant); + auto triangleBoundsRec = dynamic_cast<const TriangleBounds*>(&triangleSrfRec.bounds()); + for(size_t i=0;i<3;i++) { + Vector2D exp = triangleBounds->vertices().at(i); + Vector2D act = triangleBoundsRec->vertices().at(i); + BOOST_CHECK_CLOSE(exp.x(), act.x(), 1e-4); + BOOST_CHECK_CLOSE(exp.y(), act.y(), 1e-4); + } + BOOST_TEST(rot->isApprox(triangleSrfRec.transform(), 1e-4)); + } -- GitLab