File indexing completed on 2025-10-30 07:54:53
0001
0002
0003
0004
0005
0006
0007
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
0026 ProtoSurfaces pSurfaces;
0027 ProtoGrid pGrid;
0028 ProtoAssociations pAssociations;
0029
0030 const auto& surfaces = surfaceArray.surfaces();
0031
0032
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
0042 std::vector<double> edges0;
0043 std::vector<double> edges1;
0044
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
0055 if (binning[0] == AxisDirection::AxisPhi &&
0056 binning[1] == AxisDirection::AxisZ) {
0057 vType = cylinder;
0058
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
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
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
0079 vType = polar;
0080 edges0 = axes[0]->getBinEdges();
0081 edges1 = axes[1]->getBinEdges();
0082 pGrid._type = actsvg::proto::grid::e_r_phi;
0083 }
0084
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
0094 std::vector<actsvg::svg::object> templateObjects;
0095 std::vector<const SurfaceBounds*> templateBounds;
0096
0097
0098 double radius = 0.;
0099 for (const auto& sf : surfaces) {
0100
0101 const SurfaceBounds& sBounds = sf->bounds();
0102 radius += VectorHelpers::perp(sf->center(gctx));
0103
0104
0105 auto sameBounds = [&](const SurfaceBounds* test) {
0106 return ((*test) == sBounds);
0107 };
0108
0109
0110 if (std::ranges::none_of(templateBounds, sameBounds)) {
0111
0112 SurfaceConverter::Options sOptions;
0113 sOptions.templateSurface = true;
0114
0115 auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0116 if (sfStyle != cOptions.surfaceStyles.end()) {
0117 sOptions.style = *sfStyle;
0118 }
0119
0120
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
0132 if (pGrid._type == actsvg::proto::grid::e_z_phi) {
0133 pGrid._reference_r = static_cast<float>(radius);
0134 }
0135
0136
0137 for (const auto& sf : surfaces) {
0138
0139 SurfaceConverter::Options sOptions;
0140 sOptions.templateSurface = vType != cylinder;
0141
0142 auto sfStyle = cOptions.surfaceStyles.find(sf->geometryId());
0143 if (sfStyle != cOptions.surfaceStyles.end()) {
0144 sOptions.style = *sfStyle;
0145 }
0146
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
0155 if (vType == planar || vType == polar) {
0156
0157
0158 const auto& sTransform = sf->transform(gctx);
0159 Vector3 localA = sTransform.rotation().col(0);
0160 Vector3 localZ = sTransform.rotation().col(2);
0161
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
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
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
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
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
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
0211 return {pSurfaces, pGrid, pAssociations};
0212 }