From 4ec52311775b08460fce47225db3f4dabcb61995 Mon Sep 17 00:00:00 2001 From: Fred <92879080+fredevb@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:06:04 +0200 Subject: [PATCH] feat: visualization of grids (#552) Added visualization of acceleration grids. Furthermore simplified parts of the illustrator class. Note that I have added a webpage generation tool with detray in mind to ACTSVG which can be used for debugging purposes to easily merge and switch between svgs --- extern/actsvg/CMakeLists.txt | 2 +- .../plugins/svgtools/conversion/grid.hpp | 164 ++++++++++++++++ .../conversion/information_section.hpp | 2 + .../conversion/intersection_record.hpp | 26 ++- .../plugins/svgtools/conversion/landmark.hpp | 17 +- .../plugins/svgtools/conversion/link.hpp | 4 +- .../detray/plugins/svgtools/illustrator.hpp | 184 ++++++++++-------- .../plugins/svgtools/styling/styling.hpp | 48 ++++- .../detray/plugins/svgtools/utils/groups.hpp | 33 ++++ .../svgtools/utils/intersection_utils.hpp | 29 +++ .../plugins/svgtools/utils/volume_utils.hpp | 13 ++ tests/unit_tests/svgtools/CMakeLists.txt | 12 ++ tests/unit_tests/svgtools/detectors.cpp | 10 +- tests/unit_tests/svgtools/grids.cpp | 56 ++++++ tests/unit_tests/svgtools/groups.cpp | 42 ++-- tests/unit_tests/svgtools/intersections.cpp | 25 ++- tests/unit_tests/svgtools/landmarks.cpp | 53 +++++ tests/unit_tests/svgtools/masks.cpp | 11 +- tests/unit_tests/svgtools/surfaces.cpp | 20 +- tests/unit_tests/svgtools/trajectories.cpp | 54 +++-- tests/unit_tests/svgtools/volumes.cpp | 20 +- tests/unit_tests/svgtools/web.cpp | 131 +++++++++++++ 22 files changed, 792 insertions(+), 164 deletions(-) create mode 100644 plugins/svgtools/include/detray/plugins/svgtools/conversion/grid.hpp create mode 100644 plugins/svgtools/include/detray/plugins/svgtools/utils/groups.hpp create mode 100644 plugins/svgtools/include/detray/plugins/svgtools/utils/intersection_utils.hpp create mode 100644 tests/unit_tests/svgtools/grids.cpp create mode 100644 tests/unit_tests/svgtools/landmarks.cpp create mode 100644 tests/unit_tests/svgtools/web.cpp diff --git a/extern/actsvg/CMakeLists.txt b/extern/actsvg/CMakeLists.txt index e4d17736c..9f79014bd 100644 --- a/extern/actsvg/CMakeLists.txt +++ b/extern/actsvg/CMakeLists.txt @@ -19,7 +19,7 @@ message( STATUS "Building actsvg as part of the Detray project" ) # Declare where to get Actsvg from. set( DETRAY_ACTSVG_GIT_REPOSITORY "https://github.com/acts-project/actsvg.git" CACHE STRING "Git repository to take actsvg from" ) -set( DETRAY_ACTSVG_GIT_TAG "v0.4.35" CACHE STRING "Version of actsvg to build" ) +set( DETRAY_ACTSVG_GIT_TAG "v0.4.37" CACHE STRING "Version of actsvg to build" ) mark_as_advanced( DETRAY_ACTSVG_GIT_REPOSITORY DETRAY_ACTSVG_GIT_TAG ) FetchContent_Declare( actsvg GIT_REPOSITORY "${DETRAY_ACTSVG_GIT_REPOSITORY}" diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/grid.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/grid.hpp new file mode 100644 index 000000000..a1bc5dde4 --- /dev/null +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/grid.hpp @@ -0,0 +1,164 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +#pragma once + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/definitions/units.hpp" +#include "detray/grids/axis.hpp" + +// Actsvg include(s) +#include "actsvg/proto/grid.hpp" + +// System include(s) +#include +#include +#include +#include + +namespace detray::svgtools::conversion { + +/// A functor to access the bin edges. +template +struct edge_getter { + template + DETRAY_HOST_DEVICE inline auto operator()( + [[maybe_unused]] const group_t& group, + [[maybe_unused]] const index_t index) const { + using accel_t = typename group_t::value_type; + if constexpr (detray::detail::is_grid_v) { + const auto grid = group[index]; + const auto axis_bin_edges = + grid.axes().template get_axis().bin_edges(); + std::vector edges; + std::copy(axis_bin_edges.cbegin(), axis_bin_edges.cend(), + std::back_inserter(edges)); + return edges; + } + return std::vector{}; + } +}; + +/// @return the bin edges of the grid. +template +auto bin_edges(const detector_t& detector, const link_t& link) { + using d_scalar_t = typename detector_t::scalar_type; + return detector.accelerator_store() + .template visit>(link); +} + +// Calculating r under the assumption that the cylinder grid is closed in phi: +// (bin_edge_min - bin_edge_max) / (2*pi). +template +auto r_phi_split(const std::vector& edges_rphi) { + const auto r = edges_rphi.back() * detray::constant::inv_pi; + std::vector edges_phi; + std::transform(edges_rphi.cbegin(), edges_rphi.cend(), + std::back_inserter(edges_phi), + [r](d_scalar_t e) { return e / r; }); + return std::tuple(edges_phi, r); +} + +/// @returns the actsvg grid type and edge values for a detray cylinder +/// grid. +template +auto cylinder2_grid_type_and_edges(const detector_t& detector, + const link_t& link, const view_t&) { + assert(link.id() == detector_t::accel::id::e_cylinder2_grid); + auto edges_rphi = bin_edges(detector, link); + auto edges_z = bin_edges(detector, link); + auto [edges_phi, r] = r_phi_split(edges_rphi); + std::vector edges_r{r, r}; + + if (std::is_same_v) { + return std::tuple(actsvg::proto::grid::e_r_phi, edges_r, edges_phi); + } + if (std::is_same_v) { + return std::tuple(actsvg::proto::grid::e_x_y, edges_z, edges_r); + } + if (std::is_same_v) { + return std::tuple(actsvg::proto::grid::e_x_y, edges_z, edges_phi); + } + if (std::is_same_v) { + return std::tuple(actsvg::proto::grid::e_x_y, edges_z, edges_rphi); + } + using scalar_t = typename detector_t::scalar_type; + return std::tuple(actsvg::proto::grid::e_x_y, std::vector{}, + std::vector{}); +} + +/// @returns the actsvg grid type and edge values for a detray disc grid. +template +auto disc_grid_type_and_edges(const detector_t& detector, const link_t& link, + const view_t&) { + assert(link.id() == detector_t::accel::id::e_disc_grid); + auto edges_r = bin_edges(detector, link); + auto edges_phi = bin_edges(detector, link); + + if (std::is_same_v) { + return std::tuple(actsvg::proto::grid::e_r_phi, edges_r, edges_phi); + } + using scalar_t = typename detector_t::scalar_type; + return std::tuple(actsvg::proto::grid::e_x_y, std::vector{}, + std::vector{}); +} + +/// @returns the detray grids respective actsvg grid type and edge +/// values. +template +auto get_type_and_axes(const detector_t& detector, const link_t& link, + const view_t& view) { + using accel_ids_t = typename detector_t::accel::id; + switch (link.id()) { + case accel_ids_t::e_cylinder2_grid: { + return cylinder2_grid_type_and_edges(detector, link, view); + } + case accel_ids_t::e_disc_grid: { + return disc_grid_type_and_edges(detector, link, view); + } + default: { + using scalar_t = typename detector_t::scalar_type; + return std::tuple(actsvg::proto::grid::e_x_y, + std::vector{}, std::vector{}); + } + } +} + +/// @brief Converts a detray grid to a actsvg proto grid. +/// @param detector the detector +/// @param index the index of the grid's volume +/// @param view the view +/// @returns a proto grid +template +std::optional grid(const detector_t& detector, + const std::size_t index, + const view_t& view) { + using d_scalar_t = typename detector_t::scalar_type; + using geo_object_ids = typename detector_t::geo_obj_ids; + + const auto vol_desc = detector.volumes()[index]; + const auto link = vol_desc.template link(); + actsvg::proto::grid p_grid; + + if (not link.is_invalid()) { + const auto [type, edges0, edges1] = + get_type_and_axes(detector, link, view); + p_grid._type = type; + std::transform(edges0.cbegin(), edges0.cend(), + std::back_inserter(p_grid._edges_0), + [](d_scalar_t v) { return static_cast(v); }); + std::transform(edges1.cbegin(), edges1.cend(), + std::back_inserter(p_grid._edges_1), + [](d_scalar_t v) { return static_cast(v); }); + return p_grid; + } + return {}; +} + +} // namespace detray::svgtools::conversion diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/information_section.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/information_section.hpp index 85e17a929..83fd420c5 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/information_section.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/information_section.hpp @@ -24,6 +24,7 @@ namespace detray::svgtools::conversion { +/// @returns a point as a string. template inline std::string point_to_string(point3_t point) { @@ -33,6 +34,7 @@ inline std::string point_to_string(point3_t point) { return stream.str(); } +/// @returns the information section for a detray surface. template inline auto information_section( const typename detector_t::geometry_context& context, diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/intersection_record.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/intersection_record.hpp index 870a92afa..7344f3c4a 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/intersection_record.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/intersection_record.hpp @@ -11,12 +11,26 @@ #include "detray/intersection/intersection.hpp" #include "detray/plugins/svgtools/conversion/landmark.hpp" #include "detray/plugins/svgtools/meta/proto/intersection_record.hpp" +#include "detray/plugins/svgtools/utils/intersection_utils.hpp" // System include(s) #include namespace detray::svgtools::conversion { +/// @returns The proto intersection record from a list of points +template +inline auto intersection_record(const container_t& points) { + using p_intersection_record_t = + svgtools::meta::proto::intersection_record; + p_intersection_record_t p_ir; + for (const auto& point : points) { + const auto p_lm = svgtools::conversion::landmark(point); + p_ir._landmarks.push_back(p_lm); + } + return p_ir; +} + /// @returns The proto intersection record of a detray intersection record. template inline auto intersection_record( @@ -27,17 +41,13 @@ inline auto intersection_record( detray::intersection2D>>& intersection_record) { - using p_intersection_record_t = - svgtools::meta::proto::intersection_record; - p_intersection_record_t p_ir; - std::vector landmarks; + std::vector points; for (const auto& record : intersection_record) { - const auto p_lm = svgtools::conversion::landmark( + const auto point = svgtools::utils::intersection_point( context, detector, record.second); - landmarks.push_back(p_lm); + points.push_back(point); } - p_ir._landmarks = landmarks; - return p_ir; + return svgtools::conversion::intersection_record(points); } } // namespace detray::svgtools::conversion \ No newline at end of file diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp index 9932527d6..16ae22f24 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp @@ -12,6 +12,7 @@ #include "detray/intersection/intersection.hpp" #include "detray/plugins/svgtools/conversion/point.hpp" #include "detray/plugins/svgtools/meta/proto/landmark.hpp" +#include "detray/plugins/svgtools/utils/intersection_utils.hpp" namespace detray::svgtools::conversion { @@ -23,15 +24,17 @@ inline auto landmark( const detray::intersection2D& d_intersection) { - using p_landmark_t = svgtools::meta::proto::landmark; - - const typename detector_t::vector3 dir{}; - const detray::surface surface{detector, d_intersection.sf_desc}; - const auto position = svgtools::conversion::point( - surface.local_to_global(context, d_intersection.local, dir)); + const auto position = + svgtools::utils::intersection_point(context, detector, d_intersection); + return svgtools::conversion::landmark(position); +} +/// @returns The proto landmark of a detray point. +template +inline auto landmark(d_point3_t& position) { + using p_landmark_t = svgtools::meta::proto::landmark; p_landmark_t p_lm; - p_lm._position = position; + p_lm._position = svgtools::conversion::point(position); return p_lm; } diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/link.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/link.hpp index fb8a58866..3a9070604 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/link.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/link.hpp @@ -29,8 +29,8 @@ inline auto link(const typename detector_t::geometry_context& context, typename detector_t::vector3 dir{}; - // Length of link arrow is currently hardcoded to 3. - constexpr double link_length = 3.; + // Length of link arrow is currently hardcoded. + constexpr double link_length = 4.; const auto [start, end] = svgtools::utils::link_points( context, detector, d_portal, dir, link_length); diff --git a/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp b/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp index 401e12365..75b57e5c9 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp @@ -9,6 +9,7 @@ // Project include(s) #include "detray/geometry/surface.hpp" +#include "detray/plugins/svgtools/conversion/grid.hpp" #include "detray/plugins/svgtools/conversion/information_section.hpp" #include "detray/plugins/svgtools/conversion/intersection_record.hpp" #include "detray/plugins/svgtools/conversion/landmark.hpp" @@ -18,6 +19,7 @@ #include "detray/plugins/svgtools/meta/display/geometry.hpp" #include "detray/plugins/svgtools/meta/display/information.hpp" #include "detray/plugins/svgtools/styling/styling.hpp" +#include "detray/plugins/svgtools/utils/groups.hpp" #include "detray/plugins/svgtools/utils/volume_utils.hpp" #include "detray/utils/ranges.hpp" @@ -26,56 +28,70 @@ // System include(s) #include +#include #include namespace detray::svgtools { -/// @brief SVG generator for a detector and related entities. +/// @brief SVG generator for a detector and related entities. Provides an easy +/// interface for displaying typical objects in a detector. For more +/// flexibility, use the tools in svgtools::conversion to convert detray objects +/// to their respective proto object. Use functions in svgtools::meta::display +/// and actsvg::display to display the proto objects. +/// @note Avoid using ids containing spaces or dashes as this seems to cause +/// issues (for instance regarding information boxes). Furthermore, to view +/// information boxes, they must be enabled in the constructor. Furthermore the +/// svg viewer (opening the file after it is created) must support animations. template class illustrator { public: illustrator() = delete; - illustrator(const detector_t& detector, - const typename detector_t::name_map& name_map) - : _detector{detector}, _name_map{name_map} {} + /// @param detector the detector + /// @param context the geometry context + /// @note information boxes are enabled by default + illustrator(const detector_t& detector, const geometry_context& context) + : _detector{detector}, _context{context} {} - illustrator(const detector_t& detector, - const typename detector_t::name_map& name_map, + /// @param detector the detector + /// @param context the geometry context + /// @param show_info boolean to choose if information boxes should be + /// included + illustrator(const detector_t& detector, const geometry_context& context, const bool show_info) - : _detector{detector}, _name_map{name_map}, _show_info{show_info} {} + : _detector{detector}, _context{context}, _show_info{show_info} {} - illustrator(const detector_t& detector, - const typename detector_t::name_map& name_map, + /// @param detector the detector + /// @param context the geometry context + /// @param show_info boolean to choose if information boxes should be + /// included + /// @param style the styling options to apply + illustrator(const detector_t& detector, const geometry_context& context, const bool show_info, const styling::style& style) : _detector{detector}, - _name_map{name_map}, + _context{context}, _show_info{show_info}, _style{style} {} /// @brief Converts a detray surface in the detector to an svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param index the index of the surface in the detector. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's surface. template - inline auto draw_surface( - const std::string& identification, - const typename detector_t::geometry_context& context, - const std::size_t index, const view_t& view) const { + inline auto draw_surface(const std::string& identification, + const std::size_t index, + const view_t& view) const { const auto surface = detray::surface{ _detector, _detector.surface_lookup()[static_cast(index)]}; - actsvg::svg::object ret; - ret._tag = "g"; - ret._id = identification; + auto ret = svgtools::utils::group(identification); actsvg::svg::object svg_sur; std::array color; if (surface.is_portal()) { auto p_portal = svgtools::conversion::portal( - context, _detector, surface); + _context, _detector, surface); svgtools::styling::apply_style(p_portal, _style._volume_style._portal_style); std::copy(p_portal._surface._fill._fc._rgb.begin(), @@ -83,7 +99,7 @@ class illustrator { svg_sur = actsvg::display::portal(identification, p_portal, view); } else { auto p_surface = svgtools::conversion::surface( - context, surface); + _context, surface); svgtools::styling::apply_style(p_surface, _style._volume_style._surface_style); std::copy(p_surface._fill._fc._rgb.begin(), @@ -92,7 +108,7 @@ class illustrator { } if (_show_info) { auto p_information_section = - svgtools::conversion::information_section(context, + svgtools::conversion::information_section(_context, surface); std::copy(color.begin(), color.end(), p_information_section._color.begin()); @@ -107,23 +123,19 @@ class illustrator { /// @brief Converts a collection of detray surfaces in the detector to an /// svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param indices the collection of surface indices in the detector to /// convert. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's surfaces. template - inline auto draw_surfaces( - const std::string& identification, - const typename detector_t::geometry_context& context, - const iterator_t& indices, const view_t& view) const { - actsvg::svg::object ret; - ret._tag = "g"; - ret._id = identification; + inline auto draw_surfaces(const std::string& identification, + const iterator_t& indices, + const view_t& view) const { + auto ret = svgtools::utils::group(identification); for (const auto index : indices) { const auto svg = draw_surface( - identification + "_surface" + std::to_string(index), context, - index, view); + identification + "_surface" + std::to_string(index), index, + view); ret.add_object(svg); } return ret; @@ -131,51 +143,33 @@ class illustrator { /// @brief Converts a detray volume in the detector to an svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param index the index of the volume in the detector. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's volume. template - inline auto draw_volume( - const std::string& identification, - const typename detector_t::geometry_context& context, - const std::size_t index, const view_t& view) const { - actsvg::svg::object ret; - ret._tag = "g"; - ret._id = identification; - const auto d_volume = - _detector.volume_by_index(static_cast(index)); - auto surface_descs = - svgtools::utils::surface_lookup(_detector, d_volume); - for (std::size_t i = 0; i < surface_descs.size(); i++) { - const auto surface_index = surface_descs[i].index(); - ret.add_object(draw_surface( - identification + "_surface" + std::to_string(surface_index), - context, surface_index, view)); - } - return ret; + inline auto draw_volume(const std::string& identification, + const std::size_t index, const view_t& view) const { + const auto surface_indices = + svgtools::utils::surface_indices(_detector, index); + return draw_surfaces(identification, surface_indices, view); } /// @brief Converts a collection of detray volumes in the detector to an /// svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param indices the collection of volume indices in the detector to /// convert. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's volumes. template - inline auto draw_volumes( - const std::string& identification, - const typename detector_t::geometry_context& context, - const iterator_t& indices, const view_t& view) const { - actsvg::svg::object ret; - ret._tag = "g"; - ret._id = identification; + inline auto draw_volumes(const std::string& identification, + const iterator_t& indices, + const view_t& view) const { + auto ret = svgtools::utils::group(identification); for (const auto index : indices) { const auto svg = draw_volume(identification + "_volume" + std::to_string(index), - context, index, view); + index, view); ret.add_object(svg); } return ret; @@ -183,29 +177,38 @@ class illustrator { /// @brief Converts a detray detector to an svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector. template - inline auto draw_detector( - const std::string& identification, - const typename detector_t::geometry_context& context, - const view_t& view) const { + inline auto draw_detector(const std::string& identification, + const view_t& view) const { auto indices = detray::views::iota(std::size_t{0u}, _detector.volumes().size()); - return draw_volumes(identification, context, indices, view); + return draw_volumes(identification, indices, view); + } + + /// @brief Converts a point to an svg. + /// @param identification the id of the svg object. + /// @param point the point. + /// @param view the display view. + /// @return actsvg::svg::object of the point. + template + inline auto draw_landmark(const std::string& identification, + const point_t& point, const view_t& view) const { + auto p_landmark = svgtools::conversion::landmark(point); + svgtools::styling::apply_style(p_landmark, _style._landmark_style); + return svgtools::meta::display::landmark(identification, p_landmark, + view); } /// @brief Converts an intersection record to an svg. /// @param identification the id of the svg object. - /// @param context the geometry context. /// @param intersection_record the intersection record. /// @param view the display view. /// @return @c actsvg::svg::object of the intersectio record. template inline auto draw_intersections( const std::string& identification, - const typename detector_t::geometry_context& context, const std::vector< std::pair( - context, _detector, intersection_record); + _context, _detector, intersection_record); svgtools::styling::apply_style(p_ir, _style._intersection_style); return svgtools::meta::display::intersection_record(identification, p_ir, view); @@ -236,6 +239,21 @@ class illustrator { view); } + /// @brief Converts a trajectory to an svg. + /// @param identification the id of the svg object. + /// @param trajectory the trajectory (eg. ray or helix). + /// @param view the display view. + /// @return actsvg::svg::object of the trajectory. + template + inline auto draw_trajectory(const std::string& identification, + const point3_container& points, + const view_t& view) const { + auto p_trajectory = svgtools::conversion::trajectory(points); + svgtools::styling::apply_style(p_trajectory, _style._trajectory_style); + return svgtools::meta::display::trajectory(identification, p_trajectory, + view); + } + /// @brief Converts a trajectory and its intersection record to an svg with /// a related coloring. /// @param identification the id of the svg object. @@ -248,7 +266,6 @@ class illustrator { typename transform3_t> inline auto draw_intersections_and_trajectory( const std::string& identification, - const typename detector_t::geometry_context& context, std::vector< std::pair& trajectory, const view_t& view) const { - actsvg::svg::object ret; - ret._tag = "g"; - ret._id = identification; + auto ret = svgtools::utils::group(identification); auto i_style = svgtools::styling::copy_fill_colors( _style._intersection_style, _style._trajectory_style); auto p_ir = svgtools::conversion::intersection_record( - context, _detector, intersection_record); + _context, _detector, intersection_record); svgtools::styling::apply_style(p_ir, i_style); - ret.add_object(svgtools::meta::display::intersection_record( - identification + "_record", p_ir, view)); ret.add_object( draw_trajectory(identification + "_trajectory", trajectory, view)); + ret.add_object(svgtools::meta::display::intersection_record( + identification + "_record", p_ir, view)); return ret; } + template + std::optional draw_grid( + const std::string& identification, const std::size_t index, + const view_t& view) const { + if (auto p_grid_ptr = svgtools::conversion::grid( + _detector, index, view)) { + svgtools::styling::apply_style(*p_grid_ptr, _style._grid_style); + return actsvg::display::grid(identification, *p_grid_ptr); + } + return {}; + } + private: using point3 = std::array; using point3_container = std::vector; + using geometry_context = typename detector_t::geometry_context; - const actsvg::point2 _info_screen_offset{-400, 400}; + const actsvg::point2 _info_screen_offset{-300, 300}; const detector_t& _detector; - const typename detector_t::name_map& _name_map; - const bool _show_info = false; + const geometry_context& _context; + const bool _show_info = true; const styling::style _style = styling::style1; }; diff --git a/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp b/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp index 6fc29d024..8981c2be3 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp @@ -81,9 +81,15 @@ std::vector green_theme(const actsvg::scalar opacity) { } // namespace colors +struct grid_style { + actsvg::scalar _stroke_width; +}; + struct landmark_style { std::vector _fill_colors; + actsvg::scalar _stroke_width; actsvg::scalar _marker_size; + std::string _marker_type; }; struct trajectory_style { @@ -115,11 +121,13 @@ struct style { volume_style _volume_style; landmark_style _intersection_style; trajectory_style _trajectory_style; + grid_style _grid_style; + landmark_style _landmark_style; }; -const surface_style surface_style1{colors::blue_theme(0.8f), 3.f}; +const surface_style surface_style1{colors::blue_theme(0.5f), 3.f}; -const surface_style surface_style2{colors::red_theme(0.8f), 3.f}; +const surface_style surface_style2{colors::red_theme(0.5f), 3.f}; const link_style link_style1{1.2f}; @@ -127,11 +135,16 @@ const portal_style portal_style1{surface_style2, link_style1, false}; const volume_style volume_style1{surface_style1, portal_style1}; -const landmark_style landmark_style1{colors::black_theme(0.8f), 5.f}; +const landmark_style landmark_style1{colors::black_theme(1.f), 1.f, 5.f, "x"}; -const trajectory_style trajectory_style1{colors::green_theme(1.f), 1.f}; +const landmark_style landmark_style2{colors::black_theme(1.f), 1.f, 3.f, "o"}; -const style style1{volume_style1, landmark_style1, trajectory_style1}; +const grid_style grid_style1{2.f}; + +const trajectory_style trajectory_style1{colors::green_theme(1.f), 3.f}; + +const style style1{volume_style1, landmark_style1, trajectory_style1, + grid_style1, landmark_style2}; /// @brief Sets the style of the proto surface. template @@ -179,6 +192,19 @@ void apply_style(actsvg::proto::volume& p_volume, } } +/// @brief Sets the style of the proto landmark. +template +void apply_style(meta::proto::landmark& p_landmark, + const landmark_style& styling) { + const auto fill_color = colors::pick_random(styling._fill_colors); + const auto fill = actsvg::style::fill(fill_color); + const auto stroke = + actsvg::style::stroke(fill_color, styling._stroke_width); + const auto marker = actsvg::style::marker{ + styling._marker_type, styling._marker_size, fill, stroke}; + p_landmark._marker = marker; +} + /// @brief Sets the style of the proto intersection record. template void apply_style( @@ -186,9 +212,10 @@ void apply_style( const landmark_style& styling) { const auto fill_color = colors::pick_random(styling._fill_colors); const auto fill = actsvg::style::fill(fill_color); - const auto stroke = actsvg::style::stroke(fill_color, 3.f); - const auto marker = - actsvg::style::marker{"x", styling._marker_size, fill, stroke}; + const auto stroke = + actsvg::style::stroke(fill_color, styling._stroke_width); + const auto marker = actsvg::style::marker{ + styling._marker_type, styling._marker_size, fill, stroke}; for (auto& p_landmark : p_intersection_record._landmarks) { p_landmark._marker = marker; } @@ -203,6 +230,11 @@ void apply_style(meta::proto::trajectory& p_trajectory, actsvg::style::stroke(fill_color, styling._stroke_width); } +/// @brief Sets the style of the proto grid. +void apply_style(actsvg::proto::grid& p_grid, const grid_style& styling) { + p_grid._stroke._width = styling._stroke_width; +} + template auto copy_fill_colors(style1_t target, const style2_t& reference) { target._fill_colors = reference._fill_colors; diff --git a/plugins/svgtools/include/detray/plugins/svgtools/utils/groups.hpp b/plugins/svgtools/include/detray/plugins/svgtools/utils/groups.hpp new file mode 100644 index 000000000..70b047b06 --- /dev/null +++ b/plugins/svgtools/include/detray/plugins/svgtools/utils/groups.hpp @@ -0,0 +1,33 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +#pragma once + +// Actsvg include(s) +#include "actsvg/core.hpp" + +// System include(s) +#include +#include + +namespace detray::svgtools::utils { + +template +auto group(const std::string& identification, const iterator_t& iterator) { + actsvg::svg::object ret; + ret._tag = "g"; + ret._id = identification; + for (const auto& item : iterator) { + ret.add_object(item); + } + return ret; +} + +auto group(const std::string& identification) { + return group(identification, std::vector{}); +} +} // namespace detray::svgtools::utils \ No newline at end of file diff --git a/plugins/svgtools/include/detray/plugins/svgtools/utils/intersection_utils.hpp b/plugins/svgtools/include/detray/plugins/svgtools/utils/intersection_utils.hpp new file mode 100644 index 000000000..dfbcc564e --- /dev/null +++ b/plugins/svgtools/include/detray/plugins/svgtools/utils/intersection_utils.hpp @@ -0,0 +1,29 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +#pragma once + +// Project include(s) +#include "detray/geometry/surface.hpp" +#include "detray/intersection/intersection.hpp" + +namespace detray::svgtools::utils { + +/// @returns detray point of an intersection. +template +inline auto intersection_point( + const typename detector_t::geometry_context& context, + const detector_t& detector, + const detray::intersection2D& + d_intersection) { + const typename detector_t::vector3 dir{}; + const detray::surface surface{detector, d_intersection.sf_desc}; + return surface.local_to_global(context, d_intersection.local, dir); +} + +} // namespace detray::svgtools::utils \ No newline at end of file diff --git a/plugins/svgtools/include/detray/plugins/svgtools/utils/volume_utils.hpp b/plugins/svgtools/include/detray/plugins/svgtools/utils/volume_utils.hpp index 9b5bc4e1a..af08a6db2 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/utils/volume_utils.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/utils/volume_utils.hpp @@ -23,4 +23,17 @@ auto surface_lookup(const detector_t& detector, } return descriptors; } + +template +auto surface_indices(const detector_t& detector, const dindex volume_index) { + const auto d_volume = + detector.volume_by_index(static_cast(volume_index)); + const auto descriptors = surface_lookup(detector, d_volume); + std::vector ret; + for (const auto& desc : descriptors) { + ret.push_back(desc.index()); + } + return ret; +} + } // namespace detray::svgtools::utils diff --git a/tests/unit_tests/svgtools/CMakeLists.txt b/tests/unit_tests/svgtools/CMakeLists.txt index 1c6f7be92..b68ade4e3 100644 --- a/tests/unit_tests/svgtools/CMakeLists.txt +++ b/tests/unit_tests/svgtools/CMakeLists.txt @@ -36,3 +36,15 @@ detray_add_test( svgtools_intersections detray_add_test( svgtools_trajectories "trajectories.cpp" LINK_LIBRARIES GTest::gtest_main detray_tests_common detray::core_array actsvg::core actsvg::meta detray::svgtools) + +detray_add_test( svgtools_grids + "grids.cpp" + LINK_LIBRARIES GTest::gtest_main detray_tests_common detray::core_array actsvg::core actsvg::meta detray::svgtools) + +detray_add_test( svgtools_land_marks + "landmarks.cpp" + LINK_LIBRARIES GTest::gtest_main detray_tests_common detray::core_array actsvg::core actsvg::meta detray::svgtools) + +detray_add_test( svgtools_web + "web.cpp" + LINK_LIBRARIES GTest::gtest_main detray_tests_common detray::core_array actsvg::core actsvg::meta detray::svgtools actsvg::web) diff --git a/tests/unit_tests/svgtools/detectors.cpp b/tests/unit_tests/svgtools/detectors.cpp index 527913df3..26a9c10f8 100644 --- a/tests/unit_tests/svgtools/detectors.cpp +++ b/tests/unit_tests/svgtools/detectors.cpp @@ -36,22 +36,22 @@ int main(int, char**) { const actsvg::views::z_r zr; // Creating the detector and geomentry context. - using toy_detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - toy_detector_t::geometry_context context{}; + using detector_t = decltype(det); + detector_t::geometry_context context{}; // Creating the svg generator for the detector. - detray::svgtools::illustrator il{det, names, true}; + detray::svgtools::illustrator il{det, context}; // Get the svg of the toy detetector in x-y view. - const auto svg_xy = il.draw_detector("detector_xy", context, xy); + const auto svg_xy = il.draw_detector("detector_xy", xy); // Write the svg of toy detector. detray::svgtools::write_svg("test_svgtools_detector_xy.svg", {xy_axis, svg_xy}); // Get the svg of the toy detetector in z-r view. - const auto svg_zr = il.draw_detector("detector_zr", context, zr); + const auto svg_zr = il.draw_detector("detector_zr", zr); // Write the svg of toy detector in z-r view detray::svgtools::write_svg("test_svgtools_detector_zr.svg", {zr_axis, svg_zr}); diff --git a/tests/unit_tests/svgtools/grids.cpp b/tests/unit_tests/svgtools/grids.cpp new file mode 100644 index 000000000..f2e9daa52 --- /dev/null +++ b/tests/unit_tests/svgtools/grids.cpp @@ -0,0 +1,56 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/detectors/create_toy_geometry.hpp" +#include "detray/plugins/svgtools/illustrator.hpp" +#include "detray/plugins/svgtools/writer.hpp" + +// Vecmem include(s) +#include + +int main(int, char**) { + + // This test creates the visualization using the illustrator class. + // However, for full control over the process, it is also possible to use + // the tools in svgstools::conversion, svgstools::display, and + // actsvg::display by converting the object to a proto object, optionally + // styling it, and then displaying it. + + // Creating the detector and geomentry context. + vecmem::host_memory_resource host_mr; + const auto [det, names] = detray::create_toy_geometry(host_mr); + using detector_t = decltype(det); + detector_t::geometry_context context{}; + + // Creating the view. + const actsvg::views::x_y view; + + // Creating the svg generator for the detector. + detray::svgtools::illustrator il{det, context, true}; + + // In this example we want to draw the grids of the volumes with indices 0, + // 1, ... in the detector. + std::vector indices = { + 0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, 7UL, 8UL, 9UL, + 10UL, 11UL, 12UL, 13UL, 14UL, 15UL, 16UL, 17UL, 18UL, 19UL}; + + for (const auto i : indices) { + std::string name = "volume" + std::to_string(i) + "_grid"; + // Draw the grid for volume i. + if (auto grid_svg_ptr = il.draw_grid(name, i, view)) { + // Draw volume i. + const auto volume_svg = il.draw_volume("volume", i, view); + // Write volume i and its grid + // (the grid is last in the list since we want it to be displayed on + // top of the volume). + detray::svgtools::write_svg(name + ".svg", + {volume_svg, *grid_svg_ptr}); + } + } +} \ No newline at end of file diff --git a/tests/unit_tests/svgtools/groups.cpp b/tests/unit_tests/svgtools/groups.cpp index b540f945b..95cb21d7a 100644 --- a/tests/unit_tests/svgtools/groups.cpp +++ b/tests/unit_tests/svgtools/groups.cpp @@ -6,6 +6,8 @@ */ // Project include(s) +#include "detray/plugins/svgtools/utils/groups.hpp" + #include "detray/core/detector.hpp" #include "detray/detectors/create_toy_geometry.hpp" #include "detray/plugins/svgtools/illustrator.hpp" @@ -32,44 +34,54 @@ int main(int, char**) { const actsvg::views::z_r zr; // Creating the detector and geomentry context. - using toy_detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - toy_detector_t::geometry_context context{}; + using detector_t = decltype(det); + detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, names}; + const detray::svgtools::illustrator il{det, context}; // Visualisation of a group of surfaces. const std::array surface_group_indices{1UL, 100UL, 10UL, 200UL}; - const auto svg_surface_group_xy = il.draw_surfaces( - "my_surface_group1_xy", context, surface_group_indices, xy); + const auto svg_surface_group_xy = + il.draw_surfaces("my_surface_group1_xy", surface_group_indices, xy); detray::svgtools::write_svg("test_svgtools_surface_group_xy.svg", {axes, svg_surface_group_xy}); - const auto svg_surface_group_zr = il.draw_surfaces( - "my_surface_group1_zr", context, surface_group_indices, zr); + const auto svg_surface_group_zr = + il.draw_surfaces("my_surface_group1_zr", surface_group_indices, zr); detray::svgtools::write_svg("test_svgtools_surface_group_zr.svg", {axes, svg_surface_group_zr}); // Visualisation of a group of volumes. const std::array volume_group_indices{3UL, 5UL}; - const auto svg_volume_group_xy = il.draw_volumes( - "my_volume_group1_xy", context, volume_group_indices, xy); + const auto svg_volume_group_xy = + il.draw_volumes("my_volume_group1_xy", volume_group_indices, xy); detray::svgtools::write_svg("test_svgtools_volume_group_xy.svg", {axes, svg_volume_group_xy}); - const auto svg_volume_group_zr = il.draw_volumes( - "my_volume_group1_zr", context, volume_group_indices, zr); + const auto svg_volume_group_zr = + il.draw_volumes("my_volume_group1_zr", volume_group_indices, zr); detray::svgtools::write_svg("test_svgtools_volume_group_zr.svg", {axes, svg_volume_group_zr}); - // Writing SVGs to a combined file. - // NOTE: The all svg object's identification must be unique in the - // file! + // We can also use the svgtools::utils to group actsvg::svg::objects into + // one. + auto svg_combined_group = detray::svgtools::utils::group("combined_group"); + svg_combined_group.add_object(svg_surface_group_xy); + svg_combined_group.add_object(svg_volume_group_zr); + + detray::svgtools::write_svg("test_svgtools_combined_group1.svg", + {axes, svg_combined_group}); + + // Alternatively, this is equivalent to: detray::svgtools::write_svg( - "test_svgtools_volume_and_surface_group.svg", + "test_svgtools_combined_group2.svg", {axes, svg_surface_group_xy, svg_volume_group_zr}); + + // NOTE: The all svg object's identification must be unique in the + // file! } diff --git a/tests/unit_tests/svgtools/intersections.cpp b/tests/unit_tests/svgtools/intersections.cpp index 00efe6c5a..8c763b5d4 100644 --- a/tests/unit_tests/svgtools/intersections.cpp +++ b/tests/unit_tests/svgtools/intersections.cpp @@ -27,6 +27,12 @@ int main(int, char**) { + // This test creates the visualization using the illustrator class. + // However, for full control over the process, it is also possible to use + // the tools in svgstools::conversion, svgstools::display, and + // actsvg::display by converting the object to a proto object, optionally + // styling it, and then displaying it. + // Axes. const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, @@ -36,16 +42,18 @@ int main(int, char**) { const actsvg::views::z_r view; // Creating the detector and geomentry context. - using detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); + using detector_t = decltype(det); detector_t::geometry_context context{}; using transform3_t = typename detector_t::transform3; - // Svg for the detector. - const detray::svgtools::illustrator il{det, names}; - const auto svg_det = il.draw_detector("detector", context, view); + // Creating the illustrator. + const detray::svgtools::illustrator il{det, context}; + + // Drawing the detector. + const auto svg_det = il.draw_detector("detector", view); // Creating the rays. using generator_t = @@ -61,11 +69,14 @@ int main(int, char**) { const auto intersection_record = detray::particle_gun::shoot_particle(det, test_ray); - const std::string name = "record" + std::to_string(index); + const std::string name = + "test_svgtools_intersection_record" + std::to_string(index); + + // Drawing the intersections. const auto svg_ir = - il.draw_intersections(name, context, intersection_record, view); + il.draw_intersections(name, intersection_record, view); - detray::svgtools::write_svg(name + ".svg", {svg_det, svg_ir}); + detray::svgtools::write_svg(name + ".svg", {axes, svg_det, svg_ir}); index++; } diff --git a/tests/unit_tests/svgtools/landmarks.cpp b/tests/unit_tests/svgtools/landmarks.cpp new file mode 100644 index 000000000..792e84c44 --- /dev/null +++ b/tests/unit_tests/svgtools/landmarks.cpp @@ -0,0 +1,53 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/detectors/create_toy_geometry.hpp" +#include "detray/plugins/svgtools/illustrator.hpp" +#include "detray/plugins/svgtools/writer.hpp" + +// Vecmem include(s) +#include + +// Actsvg include(s) +#include "actsvg/core.hpp" + +// System include(s) +#include + +int main(int, char**) { + + // Axes. + const auto axes = + actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, + actsvg::style::stroke(), "axis1", "axis2"); + + // Creating the view. + const actsvg::views::x_y xy; + const actsvg::views::z_r zr; + + // Creating the detector and geomentry context. + vecmem::host_memory_resource host_mr; + const auto [det, names] = detray::create_toy_geometry(host_mr); + using detector_t = decltype(det); + detector_t::geometry_context context{}; + + using point = typename detector_t::point3; + + // Creating the illustrator class. + const detray::svgtools::illustrator il{det, context}; + + // Sometimes its useful to be able to just draw a point while debugging. + // For this the draw_landmark function is available. + const point test_point{100, 50, 20}; + + const auto svg_xy = il.draw_landmark("landmark", test_point, xy); + const auto svg_zr = il.draw_landmark("landmark", test_point, zr); + detray::svgtools::write_svg("test_svgtools_landmark.svg", + {svg_xy, svg_zr, axes}); +} \ No newline at end of file diff --git a/tests/unit_tests/svgtools/masks.cpp b/tests/unit_tests/svgtools/masks.cpp index 7b1d1b635..9b18c3251 100644 --- a/tests/unit_tests/svgtools/masks.cpp +++ b/tests/unit_tests/svgtools/masks.cpp @@ -25,8 +25,9 @@ #include int main(int, char**) { + // This tests demonstrate the different masks that can be visualized. - // Axes. + // Create the axes. const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, actsvg::style::stroke()); @@ -38,8 +39,9 @@ int main(int, char**) { const typename transform_t::vector3 tr{0.f, 150.f, 0.f}; const typename toy_detector_t::transform3 transform(tr); - const actsvg::views::x_y view{}; + const actsvg::views::z_phi view{}; + // Visualize a 2D annulus. // e_min_r, e_max_r, e_min_phi_rel, e_max_phi_rel, e_average_phi, e_shift_x, // e_shift_y, e_size detray::mask> ann2D{0u, 100.f, 200.f, -1.f, @@ -51,6 +53,7 @@ int main(int, char**) { detray::svgtools::write_svg("test_svgtools_annulus2D.svg", {axes, ann2D_svg}); + // Visualize a 2D cylinder. // e_r, e_n_half_z, e_p_half_z, e_size detray::mask> cyl2D{0u, 100.f, -10.f, 10.f}; const auto cyl2D_proto = @@ -60,6 +63,7 @@ int main(int, char**) { detray::svgtools::write_svg("test_svgtools_cylinder2D.svg", {axes, cyl2D_svg}); + // Visualize a 2D rectangle. // e_half_x, e_half_y, e_size detray::mask> rec2D{0u, 100.f, 100.f}; const auto rec2D_proto = @@ -69,6 +73,7 @@ int main(int, char**) { detray::svgtools::write_svg("test_svgtools_rectangle2D.svg", {axes, rec2D_svg}); + // Visualize a 2D ring. // e_inner_r, e_outer_r, e_size detray::mask> rin2D{0u, 50.f, 100.f}; const auto rin2D_proto = @@ -77,6 +82,7 @@ int main(int, char**) { const auto rin2D_svg = actsvg::display::surface("", rin2D_proto, view); detray::svgtools::write_svg("test_svgtools_ring2D.svg", {axes, rin2D_svg}); + // Visualize a 2D trapezoid. // e_half_length_0, e_half_length_1, e_half_length_2, e_divisor, e_size detray::mask> tra2D{0u, 100.f, 50.f, 200.f}; const auto tra2D_proto = @@ -86,6 +92,7 @@ int main(int, char**) { detray::svgtools::write_svg("test_svgtools_trapezoid2D.svg", {axes, tra2D_svg}); + // Visualize a line. // e_cross_section, e_half_z detray::mask> lin2D{0u, 1.f, 100.f}; const auto lin2D_proto = diff --git a/tests/unit_tests/svgtools/surfaces.cpp b/tests/unit_tests/svgtools/surfaces.cpp index b0be55ca9..457464fd1 100644 --- a/tests/unit_tests/svgtools/surfaces.cpp +++ b/tests/unit_tests/svgtools/surfaces.cpp @@ -23,6 +23,12 @@ int main(int, char**) { + // This test creates the visualization using the illustrator class. + // However, for full control over the process, it is also possible to use + // the tools in svgstools::conversion, svgstools::display, and + // actsvg::display by converting the object to a proto object, optionally + // styling it, and then displaying it. + // Axes. const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, actsvg::style::stroke()); @@ -32,23 +38,23 @@ int main(int, char**) { const actsvg::views::z_r zr; // Creating the detector and geomentry context. - using toy_detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - toy_detector_t::geometry_context context{}; + using detector_t = decltype(det); + detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, names}; + const detray::svgtools::illustrator il{det, context}; // Indexes of the surfaces in the detector to be visualized. - std::array indices{0UL, 1UL, 2UL, 3UL}; + std::array indices{200UL, 201UL, 202UL, 203UL, 204UL}; for (std::size_t i : indices) { std::string name = "test_svgtools_surface" + std::to_string(i); - // Visualization of portal i: - const auto svg_xy = il.draw_surface(name, context, i, xy); + // Visualization of surface/portal i: + const auto svg_xy = il.draw_surface(name, i, xy); detray::svgtools::write_svg(name + "_xy.svg", {axes, svg_xy}); - const auto svg_zr = il.draw_surface(name, context, i, zr); + const auto svg_zr = il.draw_surface(name, i, zr); detray::svgtools::write_svg(name + "_zr.svg", {axes, svg_zr}); } } diff --git a/tests/unit_tests/svgtools/trajectories.cpp b/tests/unit_tests/svgtools/trajectories.cpp index 96bcfeba7..11dd009a5 100644 --- a/tests/unit_tests/svgtools/trajectories.cpp +++ b/tests/unit_tests/svgtools/trajectories.cpp @@ -27,50 +27,68 @@ int main(int, char**) { - // Axes. + // This test creates the visualization using the illustrator class. + // However, for full control over the process, it is also possible to use + // the tools in svgstools::conversion, svgstools::display, and + // actsvg::display by converting the object to a proto object, optionally + // styling it, and then displaying it. + + // Creating the axes. const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, actsvg::style::stroke(), "axis1", "axis2"); // Creating the view. - const actsvg::views::z_r view; + const actsvg::views::x_y view; // Creating the detector and geomentry context. - using detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); + using detector_t = decltype(det); detector_t::geometry_context context{}; - // Svg for the detector. - const detray::svgtools::illustrator il{det, names}; - const auto svg_det = il.draw_detector("detector", context, view); + // Creating the illustrator. + const detray::svgtools::illustrator il{det, context, true}; + + // Show the relevant volumes in the detector. + const auto svg_volumes = + il.draw_volumes("detector", std::vector{7UL, 9UL, 11UL, 13UL}, view); - // Creating the rays. + // Creating a ray. using transform3_t = typename detector_t::transform3; using vector3 = typename detector_t::vector3; - const typename detector_t::point3 ori{0.f, 0.f, 100.f}; + const typename detector_t::point3 ori{0.f, 0.f, 80.f}; const typename detector_t::point3 dir{0, 1, 1}; const detray::detail::ray ray(ori, 0.f, dir, 0.f); const auto ray_ir = detray::particle_gun::shoot_particle(det, ray); + // Draw the trajectory. const auto svg_ray = il.draw_trajectory("trajectory", ray, view); - const auto svg_ray_ir = - il.draw_intersections("record", context, ray_ir, view); - detray::svgtools::write_svg("ray.svg", {svg_det, svg_ray, svg_ray_ir}); + + // Draw the intersections. + const auto svg_ray_ir = il.draw_intersections("record", ray_ir, view); + + detray::svgtools::write_svg("test_svgtools_ray.svg", + {svg_volumes, svg_ray, svg_ray_ir}); + + // Creating a helix trajectory. // Constant magnetic field - vector3 B{1.f * detray::unit::T, - 1.f * detray::unit::T, + vector3 B{0.f * detray::unit::T, + 0.f * detray::unit::T, 1.f * detray::unit::T}; - const detray::detail::helix helix(ori, 0.f, dir, -500.f, &B); + const detray::detail::helix helix(ori, 0.f, dir, -8.f, &B); const auto helix_ir = detray::particle_gun::shoot_particle(det, helix); + // Draw the trajectory. const auto svg_helix = il.draw_trajectory("trajectory", helix, view); - const auto svg_helix_ir = - il.draw_intersections("record", context, helix_ir, view); - detray::svgtools::write_svg("helix.svg", - {svg_det, svg_helix, svg_helix_ir}); + + // Draw the intersections. + const auto svg_helix_ir = il.draw_intersections("record", helix_ir, view); + + detray::svgtools::write_svg("test_svgtools_helix.svg", + {svg_volumes, svg_helix, svg_helix_ir}); } \ No newline at end of file diff --git a/tests/unit_tests/svgtools/volumes.cpp b/tests/unit_tests/svgtools/volumes.cpp index 4c5050f28..22325eb10 100644 --- a/tests/unit_tests/svgtools/volumes.cpp +++ b/tests/unit_tests/svgtools/volumes.cpp @@ -23,6 +23,12 @@ int main(int, char**) { + // This test creates the visualization using the illustrator class. + // However, for full control over the process, it is also possible to use + // the tools in svgstools::conversion, svgstools::display, and + // actsvg::display by converting the object to a proto object, optionally + // styling it, and then displaying it. + // Axes. const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, actsvg::style::stroke()); @@ -32,22 +38,24 @@ int main(int, char**) { const actsvg::views::z_r zr; // Creating the detector and geomentry context. - using toy_detector_t = detray::detector; vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - toy_detector_t::geometry_context context{}; + using detector_t = decltype(det); + detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, names}; + const detray::svgtools::illustrator il{det, context}; // Indexes of the volumes in the detector to be visualized. - std::array indices{0UL, 1UL, 2UL, 3UL}; + std::array indices{0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, + 7UL, 8UL, 9UL, 10UL, 11UL, 12UL, 13UL, + 14UL, 15UL, 16UL, 17UL, 18UL, 19UL}; for (std::size_t i : indices) { std::string name = "test_svgtools_volume" + std::to_string(i); // Visualization of volume i: - const auto svg_xy = il.draw_volume(name, context, i, xy); + const auto svg_xy = il.draw_volume(name, i, xy); detray::svgtools::write_svg(name + "_xy.svg", {axes, svg_xy}); - const auto svg_zr = il.draw_volume(name, context, i, zr); + const auto svg_zr = il.draw_volume(name, i, zr); detray::svgtools::write_svg(name + "_zr.svg", {axes, svg_zr}); } } diff --git a/tests/unit_tests/svgtools/web.cpp b/tests/unit_tests/svgtools/web.cpp new file mode 100644 index 000000000..5223d16b7 --- /dev/null +++ b/tests/unit_tests/svgtools/web.cpp @@ -0,0 +1,131 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/detectors/create_toy_geometry.hpp" +#include "detray/intersection/detail/trajectories.hpp" +#include "detray/plugins/svgtools/illustrator.hpp" +#include "detray/plugins/svgtools/utils/groups.hpp" +#include "detray/plugins/svgtools/writer.hpp" +#include "tests/common/tools/particle_gun.hpp" + +// Vecmem include(s) +#include + +// Actsvg include(s) +#include "actsvg/core.hpp" +#include "actsvg/web/web_builder.hpp" + +// System include(s) +#include +#include +#include + +int main(int, char**) { + + // In this test we will create a web page to show the detector geometry and + // more. We will start by creating the svgs we want to include in the web + // page. + + // Axes. + const auto axes = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, + actsvg::style::stroke()); + + // Creating the views. + const actsvg::views::x_y view; + + // Creating the detector and geomentry context. + vecmem::host_memory_resource host_mr; + const auto [det, names] = detray::create_toy_geometry(host_mr); + using detector_t = decltype(det); + detector_t::geometry_context context{}; + + using transform3_t = typename detector_t::transform3; + using vector3 = typename detector_t::vector3; + + // Creating the svg generator for the detector. + const detray::svgtools::illustrator il{det, context}; + + // The vector of svgs that we want to include on the webpage. + std::vector svgs; + + // Indexes of the volumes in the detector to be visualized. + std::array indices{0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, + 7UL, 8UL, 9UL, 10UL, 11UL, 12UL, 13UL, + 14UL, 15UL, 16UL, 17UL, 18UL, 19UL}; + + // Draw the volumes and include them in the svg vector. + for (std::size_t i : indices) { + std::string name = "Volume_" + std::to_string(i); + const auto svg = il.draw_volume(name, i, view); + svgs.push_back(svg); + } + + // Draw the grids and include them in the svg vector. + for (const auto i : indices) { + std::string name = "Grid_" + std::to_string(i); + if (auto svg_ptr = il.draw_grid(name, i, view)) { + svgs.push_back(*svg_ptr); + } + } + + // Draw some example trajectories and include them in the svg vector (along + // with their intersections). + for (const auto qop : std::vector{-4, -8, -16}) { + std::string name = "Helix_qop_" + std::to_string(qop) + ")"; + + const typename detector_t::point3 ori{0.f, 0.f, 80.f}; + const typename detector_t::point3 dir{0.f, 1.f, 1.f}; + + // Create the helix trajectory. + // Constant magnetic field + vector3 B{0.f * detray::unit::T, + 0.f * detray::unit::T, + 1.f * detray::unit::T}; + + const detray::detail::helix helix( + ori, 0.f, dir, static_cast(qop), &B); + const auto helix_ir = detray::particle_gun::shoot_particle(det, helix); + + // Draw the helix trajectory. + const auto svg_helix = + il.draw_trajectory(name + "_trajectory", helix, view); + + // Draw the intersection record. + const auto svg_helix_ir = + il.draw_intersections(name + "_record", helix_ir, view); + + // We one the trajectory and intersection record to be considered as one + // svg. Thus we group them together before adding the group to the svg + // vector. + const auto svg_group = detray::svgtools::utils::group( + name, std::vector{svg_helix, svg_helix_ir}); + svgs.push_back(svg_group); + } + + // The output directory for the web page. + const auto current_directory = std::filesystem::current_path(); + + // Create the web page builder. + actsvg::web::web_builder builder{}; + + // To visualize the svg objects in a specific order we need to pass a + // comparator before we build the page. For instance we might want to + // display helices on top on the volumes (rather than the other way around). + // In this example we will alphanumeric_compare which renderes the svgs such + // that the id of the svg object with the greatest id alphanumerically will + // be displayed on top. Build the web page. + auto alphanum_cmp = actsvg::web::compare::alphanumeric; + builder.build(current_directory / "test_svgtools_website", svgs, + alphanum_cmp); + + // Once the direcroy has been created, run the server using "python3 -m + // http.server" in the directory. Subsequently connect to localhost using + // the respective port. On the web page, click and drag to move the view + // box. Use the scroll wheel to zoom. +}