Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:03:26

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