Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-30 07:54:53

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
0008 
0009 #include "ActsPlugins/ActSVG/SurfaceArraySvgConverter.hpp"
0010 
0011 #include "Acts/Surfaces/Surface.hpp"
0012 #include "Acts/Surfaces/SurfaceArray.hpp"
0013 #include "Acts/Surfaces/SurfaceBounds.hpp"
0014 #include "ActsPlugins/ActSVG/SurfaceSvgConverter.hpp"
0015 
0016 #include <algorithm>
0017 #include <numbers>
0018 
0019 using namespace Acts;
0020 
0021 ActsPlugins::Svg::ProtoIndexedSurfaceGrid
0022 ActsPlugins::Svg::SurfaceArrayConverter::convert(
0023     const GeometryContext& gctx, const SurfaceArray& surfaceArray,
0024     const SurfaceArrayConverter::Options& cOptions) {
0025   // Prepare the return objects
0026   ProtoSurfaces pSurfaces;
0027   ProtoGrid pGrid;
0028   ProtoAssociations pAssociations;
0029 
0030   const auto& surfaces = surfaceArray.surfaces();
0031 
0032   // The edges of the grid
0033   auto binning = surfaceArray.binningValues();
0034   auto axes = surfaceArray.getAxes();
0035 
0036   enum class ViewType { cylinder, polar, planar, none };
0037   using enum ViewType;
0038   ViewType vType = none;
0039 
0040   if (!binning.empty() && binning.size() == 2 && axes.size() == 2) {
0041     // The endges values
0042     std::vector<double> edges0;
0043     std::vector<double> edges1;
0044     // Helper method to convert from ACTS to Grid edges
0045     auto convertGridEdges = [](const std::vector<double>& actsEdges) {
0046       std::vector<actsvg::scalar> svgEdges;
0047       svgEdges.reserve(actsEdges.size());
0048       for (const auto ae : actsEdges) {
0049         svgEdges.push_back(static_cast<actsvg::scalar>(ae));
0050       }
0051       return svgEdges;
0052     };
0053 
0054     // Walk through the binning and translate
0055     if (binning[0] == AxisDirection::AxisPhi &&
0056         binning[1] == AxisDirection::AxisZ) {
0057       vType = cylinder;
0058       //  flip to fit with actsvg convention
0059       edges1 = axes[0]->getBinEdges();
0060       edges0 = axes[1]->getBinEdges();
0061       pGrid._type = actsvg::proto::grid::e_z_phi;
0062     } else if (binning[0] == AxisDirection::AxisPhi &&
0063                binning[1] == AxisDirection::AxisR) {
0064       vType = polar;
0065       //  flip to fit with actsvg convention
0066       edges1 = axes[0]->getBinEdges();
0067       edges0 = axes[1]->getBinEdges();
0068       pGrid._type = actsvg::proto::grid::e_r_phi;
0069     } else if (binning[0] == AxisDirection::AxisZ &&
0070                binning[1] == AxisDirection::AxisPhi) {
0071       // good
0072       vType = cylinder;
0073       edges0 = axes[0]->getBinEdges();
0074       edges1 = axes[1]->getBinEdges();
0075       pGrid._type = actsvg::proto::grid::e_z_phi;
0076     } else if (binning[0] == AxisDirection::AxisR &&
0077                binning[1] == AxisDirection::AxisPhi) {
0078       // good
0079       vType = polar;
0080       edges0 = axes[0]->getBinEdges();
0081       edges1 = axes[1]->getBinEdges();
0082       pGrid._type = actsvg::proto::grid::e_r_phi;
0083     }
0084     // Assign
0085     pGrid._edges_0 = convertGridEdges(edges0);
0086     pGrid._edges_1 = convertGridEdges(edges1);
0087   }
0088 
0089   auto [fill, stroke] = cOptions.gridOptions.style.fillAndStroke();
0090   pGrid._fill = fill;
0091   pGrid._stroke = stroke;
0092 
0093   // Find the template surfaces & prepare template objects to be assigned
0094   std::vector<actsvg::svg::object> templateObjects;
0095   std::vector<const SurfaceBounds*> templateBounds;
0096 
0097   // Estimate a reference radius
0098   double radius = 0.;
0099   for (const auto& sf : surfaces) {
0100     // Get bounds and check them
0101     const SurfaceBounds& sBounds = sf->bounds();
0102     radius += VectorHelpers::perp(sf->center(gctx));
0103 
0104     // Helper to find bounds
0105     auto sameBounds = [&](const SurfaceBounds* test) {
0106       return ((*test) == sBounds);
0107     };
0108     // Check if you have this template object already before creating new
0109     // reference bounds and new reference object
0110     if (std::ranges::none_of(templateBounds, sameBounds)) {
0111       // Let's get the right style
0112       SurfaceConverter::Options sOptions;
0113       sOptions.templateSurface = true;
0114       // Find a corresponding file in the playbook
0115       auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0116       if (sfStyle != cOptions.surfaceStyles.end()) {
0117         sOptions.style = *sfStyle;
0118       }
0119 
0120       // Create a reference surface and reference object from it
0121       auto referenceSurface = SurfaceConverter::convert(gctx, *sf, sOptions);
0122       auto referenceObject =
0123           View::xy(referenceSurface,
0124                    "Template_" + std::to_string(templateObjects.size()));
0125       templateBounds.push_back(&sBounds);
0126       templateObjects.push_back(referenceObject);
0127     }
0128   }
0129   radius /= static_cast<double>(surfaces.size());
0130 
0131   // scale the grid edges
0132   if (pGrid._type == actsvg::proto::grid::e_z_phi) {
0133     pGrid._reference_r = static_cast<float>(radius);
0134   }
0135 
0136   // Now draw the surfaces from the correct template
0137   for (const auto& sf : surfaces) {
0138     // Let's get the right style
0139     SurfaceConverter::Options sOptions;
0140     sOptions.templateSurface = vType != cylinder;
0141     // Find a corresponding file in the playbook
0142     auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0143     if (sfStyle != cOptions.surfaceStyles.end()) {
0144       sOptions.style = *sfStyle;
0145     }
0146     // Convert the surface from ACTS to actsvg
0147     auto cSurface =
0148         ActsPlugins::Svg::SurfaceConverter::convert(gctx, *sf, sOptions);
0149     cSurface._name = "Module_n_" + std::to_string(pSurfaces.size());
0150 
0151     cSurface._aux_info["grid_info"] = {
0152         "* module " + std::to_string(pSurfaces.size()) +
0153         ", surface = " + std::to_string(sf->geometryId().sensitive())};
0154     // Correct view transform for disc/planar layers
0155     if (vType == planar || vType == polar) {
0156       // Get the transform and estimate the rotation of phi
0157       // Assumes x/y view
0158       const auto& sTransform = sf->transform(gctx);
0159       Vector3 localA = sTransform.rotation().col(0);
0160       Vector3 localZ = sTransform.rotation().col(2);
0161       // Find out orientation w.r.t. global transform
0162       double projZ = localZ.dot(Vector3(0., 0., 1.));
0163       double alpha = std::atan2(localA[1], localA[0]) / std::numbers::pi * 180.;
0164       if (projZ < 0.) {
0165         alpha += 180.;
0166       }
0167       auto surfaceCenter = sf->center(gctx);
0168       // Set the transform for an eventual placement
0169       cSurface._transform._tr = {static_cast<actsvg::scalar>(surfaceCenter[0]),
0170                                  static_cast<actsvg::scalar>(surfaceCenter[1])};
0171       cSurface._transform._rot = {static_cast<actsvg::scalar>(alpha), 0., 0.};
0172     }
0173     cSurface._radii[0u] = static_cast<float>(radius);
0174     pSurfaces.push_back(cSurface);
0175   }
0176 
0177   // Create the bin associations
0178   for (unsigned int il0 = 1; il0 < pGrid._edges_0.size(); ++il0) {
0179     double p0 = 0.5 * (pGrid._edges_0[il0] + pGrid._edges_0[il0 - 1]);
0180     for (unsigned int il1 = 1; il1 < pGrid._edges_1.size(); ++il1) {
0181       double p1 = 0.5 * (pGrid._edges_1[il1] + pGrid._edges_1[il1 - 1]);
0182       // Create the fitting bin center estimates
0183       Vector3 bCenter;
0184       Vector3 bDirection = Vector3(std::sin(p1), -std::cos(p1), 0.);
0185       if (vType == polar) {
0186         bCenter = Vector3(p0 * std::cos(p1), p0 * std::sin(p1), 0.);
0187       } else if (vType == cylinder) {
0188         bCenter = Vector3(radius * std::cos(p1), radius * std::sin(p1), p0);
0189       }
0190       // Get all the bin entries and members
0191       auto bSurfaces = surfaceArray.neighbors(bCenter, bDirection);
0192       std::vector<std::size_t> binnAssoc;
0193       for (const auto& bs : bSurfaces) {
0194         auto candidate = std::ranges::find(surfaces, bs);
0195         if (candidate != surfaces.end()) {
0196           binnAssoc.push_back(std::distance(surfaces.begin(), candidate));
0197         }
0198       }
0199       pAssociations.push_back(binnAssoc);
0200       // Register the bin naming
0201       std::string binInfo = std::string("- bin : [") + std::to_string(il0) +
0202                             std::string(", ") + std::to_string(il1) +
0203                             std::string("]") + '\n';
0204       binInfo += " - center : (" + std::to_string(p0) + ", " +
0205                  std::to_string(p1) + ")";
0206 
0207       pGrid._bin_ids.push_back(binInfo);
0208     }
0209   }
0210   // Return the surfaces and the grid
0211   return {pSurfaces, pGrid, pAssociations};
0212 }