File indexing completed on 2025-01-30 09:32:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <algorithm>
0012 #include <string>
0013 #include <tuple>
0014 #include <utility>
0015 #include <vector>
0016
0017 #include "actsvg/core.hpp"
0018 #include "actsvg/proto/surface.hpp"
0019
0020 namespace actsvg {
0021
0022 using namespace defaults;
0023
0024 namespace display {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 template <typename surface_type, typename view_type>
0039 svg::object surface(const std::string& id_, const surface_type& s_,
0040 const view_type& v_, bool _b = true, bool fs_ = false,
0041 bool sc_ = false, bool dt_ = false) {
0042
0043 svg::object s;
0044
0045
0046 if (s_._template_object.is_defined()) {
0047
0048 style::transform draw_transform = s_._transform;
0049
0050 if (dt_) {
0051 draw_transform._tr = {0., 0.};
0052 draw_transform._rot = {0., 0., 0.};
0053 }
0054
0055 if (not sc_) {
0056 draw_transform._scale = {1., 1.};
0057 }
0058
0059
0060 s = draw::from_template(id_, s_._template_object, s_._fill, s_._stroke,
0061 draw_transform);
0062 return s;
0063 }
0064
0065 style::transform draw_transform = fs_ ? style::transform{} : s_._transform;
0066 draw_transform._scale = s_._transform._scale;
0067
0068
0069 if (s_._type == surface_type::e_disc) {
0070
0071
0072 if constexpr (std::is_same_v<view_type, views::x_y>) {
0073
0074
0075 if (not utils::inside_range(s_._zparameters[0u],
0076 v_._scene._range[1u])) {
0077 s._active = false;
0078 return s;
0079 }
0080
0081 if (std::abs((s_._opening[1u] - s_._opening[0u]) - 2 * M_PI) >
0082 5 * std::numeric_limits<scalar>::epsilon()) {
0083 auto view_vertices = generators::sector_contour(
0084 s_._radii[0u], s_._radii[1u], s_._opening[0u],
0085 s_._opening[1u]);
0086 s = draw::polygon(id_, view_vertices, s_._fill, s_._stroke,
0087 draw_transform);
0088 } else {
0089
0090 s = draw::circle(id_, {0., 0.}, s_._radii[1u], s_._fill,
0091 s_._stroke, draw_transform);
0092
0093
0094 if (s_._radii[0u]) {
0095
0096 std::string mask_id = id_ + "_mask";
0097
0098 auto s_c_ = s_;
0099 s_c_._radii = {0., s_._radii[1u]};
0100
0101 svg::object outer_mask =
0102 surface(id_ + "_mask_surface_outer", s_c_, v_, false);
0103 outer_mask._fill = style::fill{true};
0104 outer_mask._stroke = style::stroke{true};
0105 outer_mask._attribute_map["fill"] = "white";
0106
0107 s_c_._radii = {0., s_._radii[0u]};
0108 svg::object inner_mask =
0109 surface(id_ + "_mask_surface_inner", s_c_, v_, false);
0110 inner_mask._fill = style::fill{true};
0111 inner_mask._stroke = style::stroke{true};
0112 inner_mask._attribute_map["fill"] = "black";
0113
0114
0115 svg::object mask;
0116 mask._fill = style::fill{true};
0117 mask._stroke = style::stroke{true};
0118 mask._id = mask_id;
0119 mask._tag = "mask";
0120 mask.add_object(outer_mask);
0121 mask.add_object(inner_mask);
0122
0123
0124 s._definitions.push_back(mask);
0125 s._attribute_map["mask"] = utils::id_to_url(mask_id);
0126 }
0127 }
0128 }
0129
0130 if constexpr (std::is_same_v<view_type, views::z_r>) {
0131 scalar zpos = s_._zparameters[0u];
0132 point2 start = {zpos, s_._radii[0u]};
0133 point2 end = {zpos, s_._radii[1u]};
0134 s = draw::line(id_, start, end, s_._stroke, draw_transform);
0135 }
0136
0137 } else if (s_._type == surface_type::e_cylinder) {
0138
0139
0140 if constexpr (std::is_same_v<view_type, views::x_y>) {
0141
0142
0143 if (not utils::inside_range(s_._zparameters[0u],
0144 v_._scene._range[1u])) {
0145 s._active = false;
0146 return s;
0147 }
0148
0149 if (std::abs((s_._opening[1u] - s_._opening[0u]) - 2 * M_PI) >
0150 5 * std::numeric_limits<scalar>::epsilon()) {
0151 scalar r = s_._radii[1u];
0152 point2 start = {r * std::cos(s_._opening[0u]),
0153 r * s_._opening[0u]};
0154 point2 end = {r * std::cos(s_._opening[1u]),
0155 r * s_._opening[1u]};
0156 s = draw::arc(id_, r, start, end, style::fill({}), s_._stroke,
0157 draw_transform);
0158 } else {
0159 s = draw::circle(id_, {0., 0.}, s_._radii[1u], style::fill({}),
0160 s_._stroke, draw_transform);
0161 }
0162 }
0163
0164
0165 if constexpr (std::is_same_v<view_type, views::z_r>) {
0166 scalar zpos = s_._zparameters[0u];
0167 scalar zhalf = s_._zparameters[1u];
0168 point2 start = {zpos - zhalf, s_._radii[1u]};
0169 point2 end = {zpos + zhalf, s_._radii[1u]};
0170 s = draw::line(id_, start, end, s_._stroke, draw_transform);
0171 }
0172
0173 } else {
0174
0175
0176
0177 bool view_active = true;
0178 if constexpr (std::is_same_v<view_type, views::x_y>) {
0179 view_active = false;
0180 for (auto v : s_._vertices) {
0181 if (utils::inside_range(v[2], v_._scene._range[1u])) {
0182 view_active = true;
0183 break;
0184 }
0185 }
0186 }
0187 if (not view_active) {
0188 s._active = view_active;
0189 return s;
0190 }
0191
0192 auto view_vertices = v_(s_._vertices);
0193 s = draw::polygon(id_, view_vertices, s_._fill, s_._stroke,
0194 draw_transform);
0195 }
0196
0197 if (_b) {
0198
0199 if constexpr (std::is_same_v<view_type, views::x_y>) {
0200 if (s_._boolean_surface.size() == 1u and
0201 s_._boolean_operation == surface_type::e_subtraction) {
0202 std::string mask_id = id_ + "_mask";
0203
0204 svg::object outer_mask =
0205 surface(id_ + "_mask_surface_outer", s_, v_, false);
0206 outer_mask._fill = style::fill{true};
0207 outer_mask._stroke = style::stroke{true};
0208 outer_mask._attribute_map["fill"] = "white";
0209
0210 svg::object inner_mask = surface(id_ + "_mask_surface_inner",
0211 s_._boolean_surface[0], v_);
0212 inner_mask._fill = style::fill{true};
0213 inner_mask._stroke = style::stroke{true};
0214 inner_mask._attribute_map["fill"] = "black";
0215
0216
0217 svg::object mask;
0218 mask._fill = style::fill{true};
0219 mask._stroke = s_._stroke;
0220 mask._id = mask_id;
0221 mask._tag = "mask";
0222 mask.add_object(outer_mask);
0223 mask.add_object(inner_mask);
0224
0225
0226 s._definitions.push_back(mask);
0227 s._attribute_map["mask"] = utils::id_to_url(mask_id);
0228 }
0229 }
0230 }
0231
0232 return s;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 template <typename portal_type, typename view_type>
0245 svg::object portal_link(const std::string& id_,
0246 [[maybe_unused]] const portal_type& p_,
0247 const typename portal_type::link& link_,
0248 const view_type& v_) {
0249 svg::object l;
0250 l._tag = "g";
0251 l._id = id_;
0252
0253 scalar d_z = link_._end[2u] - link_._start[2u];
0254
0255 if constexpr (std::is_same_v<view_type, views::x_y>) {
0256 if (v_._scene._strict and d_z * v_._scene._view[1] < 0) {
0257 l._active = false;
0258 return l;
0259 }
0260 }
0261
0262 scalar d_x = link_._end[0u] - link_._start[0u];
0263 scalar d_y = link_._end[1u] - link_._start[1u];
0264 scalar d_r = std::sqrt(d_x * d_x + d_y * d_y);
0265 if (std::is_same_v<view_type, views::x_y> and
0266 d_r <= std::numeric_limits<scalar>::epsilon()) {
0267 svg::object arr_xy;
0268 arr_xy._tag = "g";
0269 arr_xy._id = id_ + "_arrow";
0270 arr_xy.add_object(draw::circle(
0271 id_ + "_arrow_top", {link_._start[0u], link_._start[1u]},
0272 link_._end_marker._size, link_._end_marker._fill));
0273
0274 if (d_z * v_._scene._view[1] < 0) {
0275 arr_xy.add_object(draw::circle(
0276 id_ + "_arrow_top_tip", {link_._start[0u], link_._start[1u]},
0277 link_._end_marker._size * 0.1, __w_fill));
0278 } else {
0279 scalar d_l_x =
0280 link_._end_marker._size * 0.9 * std::cos(0.25 * M_PI);
0281 scalar d_l_y =
0282 link_._end_marker._size * 0.9 * std::sin(0.25 * M_PI);
0283 arr_xy.add_object(
0284 draw::line(id_ + "_arrow_top_cl0",
0285 {link_._start[0u] - d_l_x, link_._start[1u] - d_l_y},
0286 {link_._start[0u] + d_l_x, link_._start[1u] + d_l_y},
0287 __w_stroke));
0288 arr_xy.add_object(
0289 draw::line(id_ + "_arrow_top_cl1",
0290 {link_._start[0u] + d_l_x, link_._start[1u] - d_l_y},
0291 {link_._start[0u] - d_l_x, link_._start[1u] + d_l_y},
0292 __w_stroke));
0293 }
0294 l.add_object(arr_xy);
0295
0296 } else {
0297 typename portal_type::container_type start_end_3d = {link_._start,
0298 link_._end};
0299 auto start_end = v_(start_end_3d);
0300
0301 l.add_object(draw::arrow(id_ + "_arrow", start_end[0u], start_end[1u],
0302 link_._stroke, link_._start_marker,
0303 link_._end_marker));
0304 }
0305 return l;
0306 }
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 template <typename portal_type, typename view_type>
0317 svg::object portal(const std::string& id_, const portal_type& p_,
0318 const view_type& v_) {
0319 svg::object p;
0320 p._tag = "g";
0321 p._id = id_;
0322 p._fill._sterile = true;
0323 p._stroke._sterile = true;
0324
0325 p.add_object(surface(id_ + "_surface", p_._surface, v_));
0326 for (auto [il, vl] : utils::enumerate(p_._volume_links)) {
0327 p.add_object(portal_link(id_ + "_volume_link_" + std::to_string(il), p_,
0328 vl, v_));
0329 }
0330
0331 return p;
0332 }
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343 template <typename volume_type, typename view_type>
0344 svg::object volume(const std::string& id_, const volume_type& dv_,
0345 const view_type& v_, bool p_ = true) {
0346 svg::object v;
0347 v._tag = "g";
0348 v._id = id_;
0349 v._fill._sterile = true;
0350 v._stroke._sterile = true;
0351
0352
0353 if (not dv_._vertices.empty()) {
0354 auto view_vertices = v_(dv_._vertices);
0355 auto pv = draw::polygon(id_ + "_volume", view_vertices, dv_._fill,
0356 dv_._stroke, dv_._transform);
0357 v.add_object(pv);
0358 } else {
0359 if (dv_._type == volume_type::type::e_cylinder and
0360 dv_._bound_values.size() >= 6u) {
0361 scalar ri = dv_._bound_values[0u];
0362 scalar ro = dv_._bound_values[1u];
0363 scalar zp = dv_._bound_values[2u];
0364 scalar zh = dv_._bound_values[3u];
0365 scalar ps = dv_._bound_values[4u];
0366 scalar ap = dv_._bound_values[5u];
0367 if constexpr (std::is_same_v<view_type, views::x_y>) {
0368
0369 typename volume_type::surface_type s;
0370 s._name = id_ + "_volume";
0371 s._radii = {ri, ro};
0372 s._opening = {ap - ps, ap + ps};
0373 s._zparameters = {zp, zh};
0374 s._fill = dv_._fill;
0375 s._stroke = dv_._stroke;
0376 v.add_object(surface(s._name, s, v_));
0377 }
0378 if constexpr (std::is_same_v<view_type, views::z_r>) {
0379 std::vector<point2> view_vertices = {
0380 {zp - zh, ri}, {zp + zh, ri}, {zp + zh, ro}, {zp - zh, ro}};
0381 auto pv = draw::polygon(id_ + "_volume", view_vertices,
0382 dv_._fill, dv_._stroke, dv_._transform);
0383 v.add_object(pv);
0384 }
0385 }
0386 }
0387
0388
0389 if (p_) {
0390 for (auto [ip, p] : utils::enumerate(dv_._portals)) {
0391 v.add_object(portal(id_ + "_portal_" + std::to_string(ip), p, v_));
0392 }
0393 }
0394 return v;
0395 }
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405 template <typename detector_type, typename view_type>
0406 svg::object detector(const std::string& id_, const detector_type& d_,
0407 const view_type& v_) {
0408 svg::object d;
0409 d._tag = "g";
0410 d._id = id_;
0411 d._fill._sterile = true;
0412 d._stroke._sterile = true;
0413
0414
0415 auto volumes = d_._volumes;
0416 std::sort(volumes.begin(), volumes.end(),
0417 [](const auto& a_, const auto& b_) {
0418 return (a_._depth_level < b_._depth_level);
0419 });
0420
0421
0422 for (const auto& v : volumes) {
0423 d.add_object(volume(v._name, v, v_, false));
0424 }
0425
0426
0427
0428 std::map<std::string, typename detector_type::volume_type::portal_type>
0429 portals;
0430
0431 for (const auto& v : volumes) {
0432 for (const auto& p : v._portals) {
0433 portals[p._name] = p;
0434 }
0435 }
0436
0437 for (const auto [n, p] : portals) {
0438 d.add_object(portal(n, p, v_));
0439 }
0440
0441 return d;
0442 }
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454 static inline svg::object eta_lines(
0455 const std::string& id_, scalar zr_, scalar rr_,
0456 const std::vector<std::tuple<std::vector<scalar>, style::stroke, bool,
0457 style::font>>& els_,
0458 const style::transform& tr_ = style::transform()) {
0459
0460 svg::object e;
0461 e._tag = "g";
0462 e._id = id_;
0463 e._transform = tr_;
0464
0465 auto theta_from_eta = [](scalar eta) -> scalar {
0466 return static_cast<scalar>(2. * std::atan(std::exp(-eta)));
0467 };
0468
0469 scalar theta_cut = std::atan2(rr_, zr_);
0470
0471 for (auto [iet, elt] : utils::enumerate(els_)) {
0472 auto stroke = std::get<style::stroke>(elt);
0473 for (auto [ie, eta] :
0474 utils::enumerate(std::get<std::vector<scalar>>(elt))) {
0475 scalar theta = theta_from_eta(eta);
0476 std::array<scalar, 2> start = {0., 0.};
0477 std::array<scalar, 2> end;
0478 if (theta < theta_cut) {
0479 end = {zr_, static_cast<scalar>(zr_ * std::tan(theta))};
0480 } else {
0481 end = {static_cast<scalar>(rr_ * 1 / std::tan(theta)), rr_};
0482 }
0483
0484 std::string uid = std::to_string(iet) + "_" + std::to_string(ie);
0485 auto e_line =
0486 draw::line(id_ + "eta_line_" + uid, start, end, stroke);
0487 e.add_object(e_line);
0488
0489 if (std::get<bool>(elt)) {
0490 auto font = std::get<style::font>(elt);
0491 end[0] +=
0492 static_cast<scalar>(std::cos(theta) * 0.5 * font._size);
0493 end[1] +=
0494 static_cast<scalar>(std::sin(theta) * 0.5 * font._size);
0495 if (eta == 0.) {
0496 end[0] -= static_cast<scalar>(0.5 * font._size);
0497 }
0498 auto e_text = utils::to_string(eta);
0499 auto e_label =
0500 draw::text(id_ + "eta_label_" + uid, end, {e_text}, font);
0501 e.add_object(e_label);
0502 }
0503 }
0504 }
0505 return e;
0506 }
0507
0508 }
0509
0510 }