From c6a13ebb098dc47e80759d584d4c6d19cedb734c Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Tue, 6 Aug 2024 16:07:28 +0200 Subject: [PATCH] adding python-json reading --- meta/include/actsvg/display/geometry.hpp | 16 +++++- meta/include/actsvg/proto/surface.hpp | 44 +++++++++++++++ python/notebooks/barrel.ipynb | 2 +- python/notebooks/endcap.ipynb | 2 +- python/python/actsvg/actsvg_json.py | 71 +++++++++++++++++++++++- python/src/display.cpp | 43 +++++++------- python/src/proto.cpp | 32 ++++++++--- 7 files changed, 174 insertions(+), 36 deletions(-) diff --git a/meta/include/actsvg/display/geometry.hpp b/meta/include/actsvg/display/geometry.hpp index 27a7caf..53aeb43 100644 --- a/meta/include/actsvg/display/geometry.hpp +++ b/meta/include/actsvg/display/geometry.hpp @@ -29,7 +29,7 @@ namespace display { * @param s_ the surface type * @param v_ the view type * @param b_ draw the boolean - * @param fs_ draw as focus + * @param fs_ draw at focus * @param sc_ draw at scale * @param dt_ draw as template * @@ -202,13 +202,23 @@ svg::object surface(const std::string& id_, const surface_type& s_, s._active = view_active; return s; } - auto view_vertices = v_.path(s_._vertices); + + // Check if the vertices have to be transformed into global at first + // place + std::vector vertices = s_._vertices; + if (s_._surface_transform.has_value()) { + const auto& sftr = s_._surface_transform.value(); + std::for_each(vertices.begin(), vertices.end(), + [&sftr](auto& v) { v = sftr.point_to_global(v); }); + } + + auto view_vertices = v_.path(vertices); if constexpr (std::is_same_v) { // Check if we have to split the surface in phi and // draw wiggle // - currently supported for rectangular surfaces only - if (s_._vertices.size() == 4u) { + if (vertices.size() == 4u) { scalar min_phi = std::numeric_limits::max(); scalar max_phi = std::numeric_limits::min(); // Pre-emptively split the vertices diff --git a/meta/include/actsvg/proto/surface.hpp b/meta/include/actsvg/proto/surface.hpp index d481365..85bbb95 100644 --- a/meta/include/actsvg/proto/surface.hpp +++ b/meta/include/actsvg/proto/surface.hpp @@ -32,6 +32,46 @@ namespace proto { template struct surface { + using point3 = typename point3_container::value_type; + + /// A transform3 structure before placement + struct transform3 { + // original translation + point3 _translation = {0., 0., 0.}; + // original rotation + std::array _rotation = { + {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}}; + // Rotate a point to the global frame + point3 rotate(const point3& p_) const { + + point3 ret{0.f, 0.f, 0.f}; + + ret[0] += _rotation[0][0] * p_[0]; + ret[1] += _rotation[1][0] * p_[0]; + ret[2] += _rotation[2][0] * p_[0]; + + ret[0] += _rotation[0][1] * p_[1]; + ret[1] += _rotation[1][1] * p_[1]; + ret[2] += _rotation[2][1] * p_[1]; + + ret[0] += _rotation[0][2] * p_[2]; + ret[1] += _rotation[1][2] * p_[2]; + ret[2] += _rotation[2][2] * p_[2]; + + return ret; + } + + /// Apply the translation and rotation + point3 point_to_global(const point3& p_) const { + // Apply the rotation + point3 ret = rotate(p_); + ret[0] += _translation[0]; + ret[1] += _translation[1]; + ret[2] += _translation[2]; + return ret; + } + }; + enum class type { e_annulus, e_cylinder, @@ -56,6 +96,10 @@ struct surface { /// The contained vertices - for polygon surfaces point3_container _vertices = {}; + /// This is the optional surface transform - to be applied at the + /// vertices before the view is created + std::optional _surface_transform = std::nullopt; + /// Dedicated regular disc/cylinder descriptions /// - if this is not applicable the _vertices view needs to be chosen std::array _radii = {0., 0.}; diff --git a/python/notebooks/barrel.ipynb b/python/notebooks/barrel.ipynb index aada077..4f2bde0 100644 --- a/python/notebooks/barrel.ipynb +++ b/python/notebooks/barrel.ipynb @@ -45,7 +45,7 @@ "# This part converts the point clouds into surface objects\n", "barrel_modules = []\n", "for i, polygon in enumerate(barrel_polygons):\n", - " barrel_modules.append(proto.surface.from_polygon('module_'+str(i), polygon, module_fill, module_stroke))" + " barrel_modules.append(proto.surface.polygon_from_vertices('module_'+str(i), polygon, module_fill, module_stroke))" ] }, { diff --git a/python/notebooks/endcap.ipynb b/python/notebooks/endcap.ipynb index 47c553d..5cd92f0 100644 --- a/python/notebooks/endcap.ipynb +++ b/python/notebooks/endcap.ipynb @@ -65,7 +65,7 @@ "# This part converts the point clouds into surface objects\n", "endcap_modules = []\n", "for i, polygon in enumerate(endcap_polygons):\n", - " endcap_modules.append(proto.surface.from_polygon('module_'+str(i), polygon, module_fill, module_stroke))\n", + " endcap_modules.append(proto.surface.polygon_from_vertices('module_'+str(i), polygon, module_fill, module_stroke))\n", "\n", "modules_xy = display.surfaces(endcap_modules, 'xy')" ] diff --git a/python/python/actsvg/actsvg_json.py b/python/python/actsvg/actsvg_json.py index 7598cd7..b86cead 100644 --- a/python/python/actsvg/actsvg_json.py +++ b/python/python/actsvg/actsvg_json.py @@ -1,6 +1,7 @@ import json as jsn import actsvg from actsvg import proto +from actsvg import style """ read a grid axis from a json file""" @@ -107,6 +108,72 @@ def read_surface_material_maps(json_surface_material_maps): @staticmethod -def read_surface(json_surface): - ps = proto.surface() +def read_surface(json_surface, apply_transform=True): + + # Construct the name + surface_name = ( + "module_vol" + + str(json_surface["volume"]) + + "_lay" + + str(json_surface["layer"]) + + "_sen" + + str(json_surface["sensitive"]) + ) + + # Read the surface description + + surface_description = json_surface["value"] + surface_translation = (0.0, 0.0, 0.0) + surface_rotation = ( + (1, 0, 0), + (0, 1, 0), + (0, 0, 1), + ) + + if apply_transform: + surface_transform = surface_description["transform"] + surface_translation = surface_transform["translation"] + if surface_transform["rotation"] is not None: + surface_rotation = surface_transform["rotation"] + surface_rotation = ( + (surface_rotation[0], surface_rotation[1], surface_rotation[2]), + (surface_rotation[3], surface_rotation[4], surface_rotation[5]), + (surface_rotation[6], surface_rotation[7], surface_rotation[8]), + ) + + surface_vertices = [] + bounds_type = surface_description["bounds"]["type"] + bounds_values = surface_description["bounds"]["values"] + if bounds_type == "TrapezoidBounds": + hx_miny = bounds_values[0] + hx_maxy = bounds_values[1] + hy = bounds_values[2] + surface_vertices = [ + (-hx_miny, -hy, 0.0), + (hx_miny, -hy, 0.0), + (hx_maxy, hy, 0.0), + (-hx_maxy, hy, 0.0), + ] + elif bounds_type == "RectangleBounds": + hx = bounds_values[0] + hy = bounds_values[1] + surface_vertices = [ + (-hx, -hy, 0.0), + (hx, -hy, 0.0), + (hx, hy, 0.0), + (-hx, hy, 0.0), + ] + else: + print("** pyactsvg **: `json.read_surface` bounds type not (yet) supported") + raise ValueError + + ps = proto.surface.polygon_from_vertices_and_transform( + surface_name, + surface_vertices, + surface_translation, + surface_rotation, + style.defaults.sensitive_fill(), + style.defaults.sensitive_stroke(), + ) + return ps diff --git a/python/src/display.cpp b/python/src/display.cpp index e58ea66..2c0d653 100644 --- a/python/src/display.cpp +++ b/python/src/display.cpp @@ -304,17 +304,16 @@ void add_display_module(context& ctx) { /// @note the surfaces will be copied to apply the style selection /// /// @return an object (sterile if now matching view type is found) - d.def( - "surfaces_as_oriented_polygons", - [](const std::vector& ss, const std::string& view) { - std::vector polygons; - for (const auto& s : ss) { - polygons.push_back(surface_as_oriented_polygon( - s, s._fill, s._stroke, view)); - } - // Return a sterile object - return polygons; - }); + d.def("surfaces_as_oriented_polygons", + [](const std::vector& ss, const std::string& view) { + std::vector polygons; + for (const auto& s : ss) { + polygons.push_back(surface_as_oriented_polygon( + s, s._fill, s._stroke, view)); + } + // Return a sterile object + return polygons; + }); /// View surfaces - with style appied /// @@ -349,17 +348,17 @@ void add_display_module(context& ctx) { /// @note the surfaces will be copied to apply the style selection /// /// @return an object (sterile if now matching view type is found) - d.def("surfaces_as_oriented_polygons", - [](const std::vector& ss, const style::fill& f, - const style::stroke& str, const std::string& view) { - std::vector polygons; - for (const auto& s : ss) { - polygons.push_back( - surface_as_oriented_polygon(s, f, str, view)); - } - // Return a sterile object - return polygons; - }); + d.def("surfaces_as_oriented_polygons", [](const std::vector& ss, + const style::fill& f, + const style::stroke& str, + const std::string& view) { + std::vector polygons; + for (const auto& s : ss) { + polygons.push_back(surface_as_oriented_polygon(s, f, str, view)); + } + // Return a sterile object + return polygons; + }); { /// View step_tracks - with style appied diff --git a/python/src/proto.cpp b/python/src/proto.cpp index 219181f..1f627cb 100644 --- a/python/src/proto.cpp +++ b/python/src/proto.cpp @@ -51,7 +51,7 @@ void add_proto_module(context& ctx) { .def_readwrite("fill", &surface::_fill) .def_readwrite("stroke", &surface::_stroke) .def_static( - "from_polygon", + "polygon_from_vertices", [](const std::string& name, const point3_collection& pcs, const style::fill& f, const style::stroke& s) { // Create the surface @@ -63,8 +63,28 @@ void add_proto_module(context& ctx) { sf._stroke = s; return sf; }, - py::arg("name"), py::arg("points"), py::arg("fill"), - py::arg("stroke")); + py::arg("name"), py::arg("vertices"), py::arg("fill"), + py::arg("stroke")) + .def_static( + "polygon_from_vertices_and_transform", + [](const std::string& name, const point3_collection& pcs, + const point3& translation, + const std::array& rotation, + const style::fill& f, const style::stroke& s) { + // Create the surface + surface sf{}; + // Set the predefined transform + sf._surface_transform = + surface::transform3{translation, rotation}; + sf._vertices = pcs; + sf._fill = f; + sf._stroke = s; + + return sf; + }, + py::arg("name"), py::arg("vertices"), + py::arg("translation"), py::arg("rotation"), + py::arg("fill"), py::arg("stroke")); } { @@ -157,7 +177,7 @@ void add_proto_module(context& ctx) { } { - // The channel class: 1D + // The channel class: 1D py::class_(p, "channel1") .def(py::init<>()) .def_readwrite("_cid", &channel1::_cid) @@ -191,10 +211,8 @@ void add_proto_module(context& ctx) { .def_readwrite("_variance", &cluster2::_variance) .def_readwrite("_correlation", &cluster2::_correlation) .def_readwrite("_truth", &cluster2::_truth) - .def_readwrite("_mc", &cluster2::_mc); - + .def_readwrite("_mc", &cluster2::_mc); } - } } // namespace python