Warning, file /acts/Python/Plugins/src/Svg.cpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Detector/Detector.hpp"
0010 #include "Acts/Detector/DetectorVolume.hpp"
0011 #include "Acts/Detector/Portal.hpp"
0012 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0013 #include "Acts/Geometry/GeometryContext.hpp"
0014 #include "Acts/Geometry/GridPortalLink.hpp"
0015 #include "Acts/Geometry/Layer.hpp"
0016 #include "Acts/Geometry/PortalLinkBase.hpp"
0017 #include "Acts/Geometry/TrackingGeometry.hpp"
0018 #include "Acts/Geometry/TrackingVolume.hpp"
0019 #include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
0020 #include "Acts/Surfaces/CylinderBounds.hpp"
0021 #include "Acts/Surfaces/DiscBounds.hpp"
0022 #include "Acts/Utilities/Enumerate.hpp"
0023 #include "Acts/Utilities/Helpers.hpp"
0024 #include "ActsPlugins/ActSVG/DetectorSvgConverter.hpp"
0025 #include "ActsPlugins/ActSVG/DetectorVolumeSvgConverter.hpp"
0026 #include "ActsPlugins/ActSVG/IndexedSurfacesSvgConverter.hpp"
0027 #include "ActsPlugins/ActSVG/LayerSvgConverter.hpp"
0028 #include "ActsPlugins/ActSVG/PortalSvgConverter.hpp"
0029 #include "ActsPlugins/ActSVG/SurfaceArraySvgConverter.hpp"
0030 #include "ActsPlugins/ActSVG/SurfaceSvgConverter.hpp"
0031 #include "ActsPlugins/ActSVG/SvgUtils.hpp"
0032 #include "ActsPlugins/ActSVG/TrackingGeometrySvgConverter.hpp"
0033 #include "ActsPython/Utilities/Helpers.hpp"
0034 #include "ActsPython/Utilities/Macros.hpp"
0035 #include <actsvg/core/draw.hpp>
0036
0037 #include <algorithm>
0038 #include <memory>
0039 #include <ranges>
0040 #include <sstream>
0041 #include <string>
0042 #include <tuple>
0043 #include <vector>
0044
0045 #include <pybind11/pybind11.h>
0046 #include <pybind11/stl.h>
0047
0048 namespace py = pybind11;
0049 using namespace pybind11::literals;
0050
0051 using namespace Acts;
0052 using namespace Acts::Experimental;
0053 using namespace ActsExamples;
0054 using namespace ActsPlugins;
0055
0056 namespace {
0057
0058
0059 using PortalCache = std::list<std::string>;
0060
0061
0062 bool viewRangeSel(const Svg::ProtoSurface& s, const Extent& vRange) {
0063 for (const auto& v : s._vertices) {
0064 if (vRange.contains(v)) {
0065 return true;
0066 }
0067 }
0068
0069 return false;
0070 };
0071
0072
0073
0074
0075
0076 using ViewAndRange = std::tuple<std::string, std::vector<std::string>, Extent>;
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 actsvg::svg::object drawDetectorVolume(const Svg::ProtoVolume& pVolume,
0087 const std::string& identification,
0088 const ViewAndRange& viewAndRange,
0089 PortalCache& portalCache) {
0090 actsvg::svg::object svgDet;
0091 svgDet._id = identification;
0092 svgDet._tag = "g";
0093
0094 const auto& [view, selection, viewRange] = viewAndRange;
0095
0096
0097 const bool all = rangeContainsValue(selection, "all");
0098 const bool sensitives = rangeContainsValue(selection, "sensitives");
0099 const bool portals = rangeContainsValue(selection, "portals");
0100 const bool materials = rangeContainsValue(selection, "materials");
0101
0102
0103 auto materialSel = [&](const Svg::ProtoSurface& s) -> bool {
0104 return (materials && s._decorations.contains("material"));
0105 };
0106
0107
0108
0109 std::vector<Svg::ProtoVolume::surface_type> sSurfaces;
0110 sSurfaces.reserve(pVolume._v_surfaces.size());
0111 for (const auto& s : pVolume._v_surfaces) {
0112 if ((all || sensitives || materialSel(s)) && viewRangeSel(s, viewRange)) {
0113 sSurfaces.push_back(s);
0114 }
0115 }
0116
0117
0118 for (const auto& vs : sSurfaces) {
0119 if (view == "xy") {
0120 svgDet.add_object(Svg::View::xy(vs, identification));
0121 } else if (view == "zr") {
0122 svgDet.add_object(Svg::View::zr(vs, identification));
0123 } else {
0124 throw std::invalid_argument("Unknown view type");
0125 }
0126 }
0127
0128
0129 std::vector<Svg::ProtoPortal> sPortals;
0130 sPortals.reserve(pVolume._portals.size());
0131 for (const auto& vp : pVolume._portals) {
0132 if ((all || portals || materialSel(vp._surface)) &&
0133 viewRangeSel(vp._surface, viewRange)) {
0134 sPortals.push_back(vp);
0135 }
0136 }
0137
0138
0139 for (const auto& vp : sPortals) {
0140 auto pgID = vp._surface._decorations.find("geo_id");
0141 std::string gpIDs = "";
0142 if (pgID != vp._surface._decorations.end()) {
0143 gpIDs = pgID->second._id;
0144 }
0145
0146 if (rangeContainsValue(portalCache, gpIDs)) {
0147 continue;
0148 }
0149
0150
0151 portalCache.insert(portalCache.begin(), gpIDs);
0152
0153 if (view == "xy") {
0154 svgDet.add_object(Svg::View::xy(vp, identification));
0155 } else if (view == "zr") {
0156 svgDet.add_object(Svg::View::zr(vp, identification));
0157 } else {
0158 throw std::invalid_argument("Unknown view type");
0159 }
0160 }
0161 return svgDet;
0162 }
0163
0164
0165 std::vector<actsvg::svg::object> drawDetector(
0166 const GeometryContext& gctx, const Detector& detector,
0167 const std::string& identification,
0168 const std::vector<std::tuple<int, Svg::DetectorVolumeConverter::Options>>&
0169 volumeIdxOpts,
0170 const std::vector<ViewAndRange>& viewAndRanges) {
0171 PortalCache portalCache;
0172
0173
0174 std::vector<actsvg::svg::object> svgDetViews;
0175 svgDetViews.reserve(viewAndRanges.size());
0176 for (unsigned int i = 0; i < viewAndRanges.size(); ++i) {
0177 actsvg::svg::object svgDet;
0178 svgDet._id = identification;
0179 svgDet._tag = "g";
0180 svgDetViews.push_back(svgDet);
0181 }
0182
0183 for (const auto& [vidx, vopts] : volumeIdxOpts) {
0184
0185 const auto& v = detector.volumes()[vidx];
0186 auto [pVolume, pGrid] =
0187 Svg::DetectorVolumeConverter::convert(gctx, *v, vopts);
0188
0189 for (auto [iv, var] : enumerate(viewAndRanges)) {
0190 auto [view, selection, range] = var;
0191
0192 auto svgVolView = drawDetectorVolume(
0193 pVolume, identification + "_vol" + std::to_string(vidx) + "_" + view,
0194 var, portalCache);
0195 svgDetViews[iv].add_object(svgVolView);
0196 }
0197 }
0198 return svgDetViews;
0199 }
0200
0201 }
0202
0203 PYBIND11_MODULE(ActsPluginsPythonBindingsSvg, svg) {
0204 using namespace Acts;
0205 using namespace ActsPlugins;
0206
0207
0208 {
0209 py::class_<actsvg::svg::object>(svg, "object")
0210 .def_readwrite("id", &actsvg::svg::object::_id);
0211
0212 py::class_<actsvg::svg::file>(svg, "file")
0213 .def(py::init<>())
0214 .def("add_object", &actsvg::svg::file::add_object)
0215 .def("add_objects", &actsvg::svg::file::add_objects)
0216 .def("clip",
0217 [](actsvg::svg::file& self, std::array<actsvg::scalar, 4> box) {
0218 self.set_view_box(box);
0219 })
0220 .def("write",
0221 [](const actsvg::svg::file& self, const std::string& filename) {
0222 std::ofstream file(filename);
0223 file << self;
0224 file.close();
0225 });
0226
0227 svg.def("toFile", &Svg::toFile, py::arg("objects"), py::arg("filename"));
0228 }
0229
0230
0231 {
0232 auto c = py::class_<Svg::Style>(svg, "Style").def(py::init<>());
0233 ACTS_PYTHON_STRUCT(c, fillColor, fillOpacity, highlightColor, highlights,
0234 strokeWidth, strokeColor, highlightStrokeWidth,
0235 highlightStrokeColor, fontSize, fontColor,
0236 quarterSegments);
0237 }
0238
0239
0240 {
0241 auto c = py::class_<Svg::SurfaceConverter::Options>(svg, "SurfaceOptions")
0242 .def(py::init<>());
0243 ACTS_PYTHON_STRUCT(c, style, templateSurface);
0244
0245
0246 py::class_<Svg::ProtoSurface>(svg, "ProtoSurface");
0247
0248
0249 svg.def("convertSurface", &Svg::SurfaceConverter::convert);
0250
0251
0252 svg.def("viewSurface", [](const Svg::ProtoSurface& pSurface,
0253 const std::string& identification,
0254 const std::string& view = "xy") {
0255 if (view == "xy") {
0256 return Svg::View::xy(pSurface, identification);
0257 } else if (view == "zr") {
0258 return Svg::View::zr(pSurface, identification);
0259 } else if (view == "zphi") {
0260 return Svg::View::zphi(pSurface, identification);
0261 } else if (view == "zrphi") {
0262 return Svg::View::zrphi(pSurface, identification);
0263 } else {
0264 throw std::invalid_argument("Unknown view type");
0265 }
0266 });
0267 }
0268
0269
0270 {
0271 auto c = py::class_<Svg::PortalConverter::Options>(svg, "PortalOptions")
0272 .def(py::init<>());
0273
0274 ACTS_PYTHON_STRUCT(c, surfaceOptions, linkLength, volumeIndices);
0275
0276
0277 py::class_<Svg::ProtoPortal>(svg, "ProtoPortal");
0278
0279
0280 svg.def("convertPortal", &Svg::PortalConverter::convert);
0281
0282
0283 svg.def("viewPortal", [](const Svg::ProtoPortal& pPortal,
0284 const std::string& identification,
0285 const std::string& view = "xy") {
0286 if (view == "xy") {
0287 return Svg::View::xy(pPortal, identification);
0288 } else if (view == "zr") {
0289 return Svg::View::zr(pPortal, identification);
0290 } else {
0291 throw std::invalid_argument("Unknown view type");
0292 }
0293 });
0294 }
0295
0296
0297 {
0298 svg.def("drawArrow", &actsvg::draw::arrow);
0299
0300 svg.def("drawText", &actsvg::draw::text);
0301
0302 svg.def("drawInfoBox", &Svg::infoBox);
0303 }
0304
0305
0306 {
0307 svg.def(
0308 "drawEtaLines",
0309 [](const std::string& id, actsvg ::scalar z, actsvg::scalar r,
0310 const std::vector<actsvg::scalar>& etaMain,
0311 actsvg::scalar strokeWidthMain, unsigned int sizeMain,
0312 bool labelMain, const std::vector<actsvg::scalar>& etaSub,
0313 actsvg::scalar strokeWidthSub, const std::vector<int> strokeDashSub,
0314 unsigned int sizeSub, bool labelSub) {
0315
0316 actsvg::style::stroke strokeMain;
0317 strokeMain._width = strokeWidthMain;
0318 actsvg::style::font fontMain;
0319 fontMain._size = sizeMain;
0320
0321 actsvg::style::stroke strokeSub;
0322 strokeSub._width = strokeWidthSub;
0323 strokeSub._dasharray = strokeDashSub;
0324 actsvg::style::font fontSub;
0325 fontSub._size = sizeSub;
0326
0327 return actsvg::display::eta_lines(
0328 id, z, r,
0329 {std::tie(etaMain, strokeMain, labelMain, fontMain),
0330 std::tie(etaSub, strokeSub, labelSub, fontSub)});
0331 });
0332 }
0333
0334 {
0335 auto gco = py::class_<Svg::GridConverter::Options>(svg, "GridOptions")
0336 .def(py::init<>());
0337 ACTS_PYTHON_STRUCT(gco, style);
0338
0339 auto isco = py::class_<Svg::IndexedSurfacesConverter::Options>(
0340 svg, "IndexedSurfacesOptions")
0341 .def(py::init<>());
0342 ACTS_PYTHON_STRUCT(isco, gridOptions);
0343 }
0344
0345
0346 {
0347 auto c = py::class_<Svg::DetectorVolumeConverter::Options>(
0348 svg, "DetectorVolumeOptions")
0349 .def(py::init<>());
0350
0351 ACTS_PYTHON_STRUCT(c, portalIndices, portalOptions, surfaceOptions,
0352 indexedSurfacesOptions);
0353
0354
0355
0356 svg.def("convertDetectorVolume", &Svg::DetectorVolumeConverter::convert);
0357
0358
0359 svg.def("drawDetectorVolume", &drawDetectorVolume);
0360 }
0361
0362
0363 {
0364 svg.def("drawIndexedSurfaces",
0365 [](const Svg::ProtoIndexedSurfaceGrid& pIndexedSurfaceGrid,
0366 const std::string& identification) {
0367 return Svg::View::xy(pIndexedSurfaceGrid, identification);
0368 });
0369 }
0370
0371
0372 { svg.def("drawDetector", &drawDetector); }
0373
0374 { svg.def("drawSurfaceArrays", &Svg::drawSurfaceArrays); }
0375
0376
0377 {
0378 using DefinedStyle = std::pair<GeometryIdentifier, Svg::Style>;
0379 using DefinedStyleSet = std::vector<DefinedStyle>;
0380
0381 auto sm = py::class_<GeometryHierarchyMap<Svg::Style>>(svg, "StyleMap")
0382 .def(py::init<DefinedStyleSet>(), py::arg("elements"));
0383
0384 auto c = py::class_<Svg::LayerConverter::Options>(svg, "LayerOptions")
0385 .def(py::init<>());
0386 ACTS_PYTHON_STRUCT(c, name, surfaceStyles, zRange, phiRange, gridInfo,
0387 moduleInfo, projectionInfo, labelProjection, labelGauge);
0388 }
0389
0390 {
0391 using DefinedLayerOptions =
0392 std::pair<GeometryIdentifier, Svg::LayerConverter::Options>;
0393 using DefinedLayerOptionsSet = std::vector<DefinedLayerOptions>;
0394
0395 auto lom =
0396 py::class_<GeometryHierarchyMap<Svg::LayerConverter::Options>>(
0397 svg, "LayerOptionMap")
0398 .def(py::init<DefinedLayerOptionsSet>(), py::arg("elements"));
0399
0400 auto c = py::class_<Svg::TrackingGeometryConverter::Options>(
0401 svg, "TrackingGeometryOptions")
0402 .def(py::init<>());
0403 ACTS_PYTHON_STRUCT(c, prefix, layerOptions);
0404 }
0405
0406
0407 {
0408 svg.def(
0409 "drawTrackingGeometry",
0410 [](const GeometryContext& gctx, const TrackingGeometry& tGeometry,
0411 const std::string& view, bool drawSurfaces, bool highlightMaterial) {
0412 std::variant<actsvg::views::x_y, actsvg::views::z_r> v;
0413 if (view == "xy") {
0414 v = actsvg::views::x_y();
0415 } else if (view == "zr") {
0416 v = actsvg::views::z_r();
0417 } else {
0418 throw std::invalid_argument("Unknown view type");
0419 }
0420
0421 return Svg::drawTrackingGeometry(gctx, tGeometry, v, drawSurfaces,
0422 highlightMaterial);
0423 },
0424 py::arg("gctx"), py::arg("tGeometry"), py::arg("view"),
0425 py::arg("drawSurfaces") = true, py::arg("highlightMaterial") = false);
0426 }
0427 }