Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-25 09:17:52

0001 // This file is part of the actsvg package.
0002 //
0003 // Copyright (C) 2022-2024 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include <string>
0012 #include <vector>
0013 
0014 #include "actsvg/core.hpp"
0015 #include "actsvg/display/geometry.hpp"
0016 #include "actsvg/proto/surface.hpp"
0017 #include "actsvg/proto/volume.hpp"
0018 #include "actsvg/styles/defaults.hpp"
0019 
0020 namespace actsvg {
0021 
0022 using namespace defaults;
0023 
0024 namespace display {
0025 
0026 /** Helper method to calculate the center
0027  *
0028  * @param vs are the vertices that build up this module
0029  *
0030  * @return the string
0031  **/
0032 template <typename point3_container>
0033 std::string center_string(const point3_container& vs) {
0034     std::string c_str = "center = (";
0035     scalar c_x = 0;
0036     scalar c_y = 0;
0037     scalar c_z = 0;
0038     for (auto& v : vs) {
0039         c_x += v[0];
0040         c_y += v[1];
0041         c_z += v[2];
0042     }
0043     c_x /= vs.size();
0044     c_y /= vs.size();
0045     c_z /= vs.size();
0046     return c_str + std::to_string(c_x) + "," + std::to_string(c_y) + ", " +
0047            std::to_string(c_z) + ")";
0048 }
0049 
0050 /** Helper method to prepare axis for a view point
0051  *
0052  * @param first_ is the first axis
0053  * @param second_ is the second axis
0054  * @param sx_ is the first axis scale
0055  * @param sy_ is the second axis scale
0056  * @param ax_ is the first axis addon
0057  * @param ay_ is the second axis addon
0058  *
0059  * @return the marker size as 1 percent of the range
0060  **/
0061 void prepare_axes(std::array<scalar, 2>& first_, std::array<scalar, 2>& second_,
0062                   scalar sx_, scalar sy_, scalar ax_ = 0., scalar ay_ = 0.);
0063 
0064 /** Helper method to get the contours
0065  *
0066  * @param s_ is the surface
0067  * @param fs_ draw in focus mode
0068  *
0069  * @return a vector of contours;
0070  **/
0071 template <typename surface_type, typename view_type = views::x_y>
0072 views::contour range_contour(const surface_type& s_,
0073                              bool fs_ = false) noexcept(false) {
0074 
0075     view_type view;
0076 
0077     using point3 = typename surface_type::point3_type;
0078 
0079     // Add the surface
0080     views::contour contour;
0081     if (s_._template_object.is_defined()) {
0082         // Use a bounding box trick
0083         // Get the contour from the template as bounding box
0084         point2 bbl = {s_._template_object._x_range[0],
0085                       s_._template_object._y_range[0]};
0086         point2 bbr = {s_._template_object._x_range[1],
0087                       s_._template_object._y_range[1]};
0088         if (not fs_) {
0089             bbl[0] += s_._transform._tr[0];
0090             bbl[1] += s_._transform._tr[1];
0091             bbr[0] += s_._transform._tr[0];
0092             bbr[1] += s_._transform._tr[1];
0093             scalar alpha = s_._transform._rot[0];
0094             if (alpha != 0.) {
0095                 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0096                 bbl = utils::rotate(bbl, alpha_rad);
0097                 bbr = utils::rotate(bbr, alpha_rad);
0098             }
0099         }
0100         contour = {bbl, bbr};
0101     } else if (not s_._vertices.empty()) {
0102         // Plain contours are present
0103         contour = view.path(s_._vertices);
0104         if (not fs_) {
0105             std::for_each(contour.begin(), contour.end(), [&](auto& v) {
0106                 scalar alpha = s_._transform._rot[0];
0107                 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0108                 v = utils::rotate(v, alpha_rad);
0109                 v[0] += s_._transform._tr[0];
0110                 v[1] += s_._transform._tr[1];
0111             });
0112         }
0113     } else if (s_._radii[1] != 0.) {
0114         // Create a contour
0115         scalar ri = s_._radii[0];
0116         scalar ro = s_._radii[1];
0117         scalar phi_low = s_._opening[0];
0118         scalar phi_high = s_._opening[1];
0119         scalar phi = 0.5_scalar * (phi_low + phi_high);
0120         scalar cos_phi_low = std::cos(phi_low);
0121         scalar sin_phi_low = std::sin(phi_low);
0122         scalar cos_phi_high = std::cos(phi_high);
0123         scalar sin_phi_high = std::cos(phi_high);
0124         /// @todo add transform
0125         point3 A = {ri * cos_phi_low, ri * sin_phi_low, 0.};
0126         point3 B = {ri * std::cos(phi), ri * std::sin(phi), 0.};
0127         point3 C = {ri * cos_phi_high, ri * sin_phi_high, 0.};
0128         point3 D = {ro * cos_phi_high, ro * sin_phi_high, 0.};
0129         point3 E = {ro * std::cos(phi), ro * std::sin(phi), 0.};
0130         point3 F = {ro * cos_phi_low, ro * sin_phi_low, 0.};
0131 
0132         std::vector<point3> vertices_disc = {A, B, C, D, E, F};
0133         contour = view.path(vertices_disc);
0134     } else {
0135         throw std::invalid_argument(
0136             "surface_sheet_xy(...) - could not estimate range.");
0137     }
0138     return contour;
0139 }
0140 
0141 /** Helper method to scale the axis accordingly
0142  *
0143  * @param cc_ is an iterable container of contours
0144  *
0145  * @return a view range
0146  **/
0147 template <typename contour_container>
0148 static std::array<std::array<scalar, 2>, 2> view_range(
0149     const contour_container& cc_) {
0150 
0151     std::array<scalar, 2> x_range = __e_object._x_range;
0152     std::array<scalar, 2> y_range = __e_object._y_range;
0153 
0154     for (auto& c : cc_) {
0155         for (auto& v : c) {
0156             x_range[0] = std::min(v[0], x_range[0]);
0157             x_range[1] = std::max(v[0], x_range[1]);
0158             y_range[0] = std::min(v[1], y_range[0]);
0159             y_range[1] = std::max(v[1], y_range[1]);
0160         }
0161     }
0162     return {x_range, y_range};
0163 }
0164 
0165 /** Helper method to process the modules, estimate the scale and the axes
0166  *
0167  * @param v_ volume of the detector
0168  * @param view_ the view used for this
0169  * @param sh_ the sheet size
0170  * @param es_ is the equal scale
0171  * @param hl_ switch highlighting on/off
0172  * @param dt_ draw template is available
0173  *
0174  * @returns the modules (per surface batch), a scale transform & the axes
0175  **/
0176 template <typename volume_type, typename view_type>
0177 std::tuple<std::vector<std::vector<svg::object>>, style::transform,
0178            std::array<std::array<scalar, 2>, 2>>
0179 process_modules(const volume_type& v_, const view_type& view_,
0180                 const std::array<scalar, 2>& sh_ = {600., 600.},
0181                 bool es_ = false, bool hl_ = true, bool dt_ = true) {
0182 
0183     using surface_type = typename volume_type::surface_type;
0184 
0185     // Axis range & pre-loop, create contours
0186     std::vector<std::vector<views::contour>> all_contours;
0187     for (const auto& surfaces : v_._surfaces) {
0188         std::vector<views::contour> contours;
0189         contours.reserve(surfaces.size());
0190         for (const auto& s : surfaces) {
0191             surface_type range_surface = s;
0192             if (not dt_) {
0193                 range_surface._template_object = svg::object{};
0194             }
0195             contours.push_back(
0196                 range_contour<surface_type, view_type>(range_surface));
0197         }
0198         all_contours.push_back(contours);
0199     }
0200 
0201     // Concatenate all contours into one for the range display
0202     std::vector<views::contour> flattened_contours;
0203     for (const auto& c : all_contours) {
0204         flattened_contours.insert(flattened_contours.end(), c.begin(), c.end());
0205     }
0206 
0207     // Get the scaling right - same scaling for all potential views
0208     auto axes = display::view_range(flattened_contours);
0209 
0210     scalar s_x = sh_[0] / (axes[0][1] - axes[0][0]);
0211     scalar s_y = sh_[1] / (axes[1][1] - axes[1][0]);
0212 
0213     if (es_) {
0214         // Harmonize the view window with equal scales
0215         s_x = s_x < s_y ? s_x : s_y;
0216         s_y = s_y < s_x ? s_y : s_x;
0217     }
0218 
0219     // Create the scale transform
0220     style::transform scale_transform;
0221     scale_transform._scale = {s_x, s_y};
0222 
0223     // Draw the modules and estimate axis ranges
0224     std::vector<std::vector<svg::object>> all_modules;
0225     for (auto [ics, contours] : utils::enumerate(all_contours)) {
0226         std::vector<svg::object> modules;
0227         modules.reserve(contours.size());
0228         for (auto [ic, c] : utils::enumerate(contours)) {
0229             surface_type draw_surface = v_._surfaces[ics][ic];
0230             draw_surface._transform._scale = {s_x, s_y};
0231             if (not hl_) {
0232                 draw_surface._fill._fc._highlight = {};
0233             }
0234             if (not dt_) {
0235                 draw_surface._template_object = svg::object{};
0236             }
0237 
0238             auto surface_module =
0239                 display::surface(draw_surface._name, draw_surface, view_,
0240                                  {true, false, true, false});
0241             modules.push_back(surface_module);
0242         }
0243         all_modules.push_back(modules);
0244     }
0245 
0246     // Prepare the axis for the view range
0247     prepare_axes(axes[0], axes[1], s_x, s_y, 30., 30.);
0248 
0249     return {all_modules, scale_transform, axes};
0250 }
0251 
0252 /** Helper method to connect the surface sheets to the
0253  * surfaces of the layer_sheets
0254  *
0255  * @tparam volume_type the type of volume (templated on point3_container)
0256  *
0257  * @param v_ the input volume
0258  * @param templates_ the given module templtes
0259  * @param o_ the object to which they are attached
0260  *
0261  **/
0262 template <typename volume_type>
0263 void connect_surface_sheets(const volume_type& v_,
0264                             std::vector<std::vector<svg::object>>& templates_,
0265                             svg::object& o_) {
0266     // Now create an item per surface
0267     for (auto [ib, surface_batch] : utils::enumerate(v_._surfaces)) {
0268         for (auto [is, s] : utils::enumerate(surface_batch)) {
0269             std::string sid = s._name;
0270 
0271             svg::object& s_sheet_s = templates_[ib][is];
0272             s_sheet_s._attribute_map["display"] = "none";
0273 
0274             // Object information to appear
0275             svg::object on;
0276             on._tag = "animate";
0277             on._attribute_map["fill"] = "freeze";
0278             on._attribute_map["attributeName"] = "display";
0279             on._attribute_map["from"] = "none";
0280             on._attribute_map["to"] = "block";
0281             on._attribute_map["begin"] = sid + __d + "mouseout";
0282 
0283             svg::object off;
0284 
0285             off._tag = "animate";
0286             off._attribute_map["fill"] = "freeze";
0287             off._attribute_map["attributeName"] = "display";
0288             off._attribute_map["to"] = "none";
0289             off._attribute_map["from"] = "block";
0290             off._attribute_map["begin"] = sid + __d + "mouseover";
0291 
0292             // Store the animation
0293             s_sheet_s._sub_objects.push_back(off);
0294             s_sheet_s._sub_objects.push_back(on);
0295 
0296             o_.add_object(s_sheet_s);
0297         }
0298     }
0299 }
0300 
0301 }  // namespace display
0302 
0303 }  // namespace actsvg