File indexing completed on 2025-01-18 09:28:07
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <algorithm>
0012 #include <exception>
0013 #include <limits>
0014 #include <string>
0015 #include <vector>
0016
0017 #include "actsvg/core.hpp"
0018 #include "actsvg/display/geometry.hpp"
0019 #include "actsvg/display/helpers.hpp"
0020 #include "actsvg/proto/cluster.hpp"
0021 #include "actsvg/proto/surface.hpp"
0022 #include "actsvg/proto/volume.hpp"
0023
0024 namespace actsvg {
0025
0026 using namespace defaults;
0027
0028 namespace display {
0029
0030 enum layer_type { e_endcap = 0, e_barrel = 1 };
0031
0032 enum sheet_type { e_module_info = 0, e_grid_info = 1 };
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename point3_container>
0046 svg::object surface_sheet_xy(const std::string& id_,
0047 const proto::surface<point3_container>& s_,
0048 const std::array<scalar, 2>& sh_ = {400., 400.},
0049 bool fs_ = false) noexcept(false) {
0050 svg::object so;
0051 so._tag = "g";
0052 so._id = id_;
0053
0054 using point3 = typename point3_container::value_type;
0055
0056 views::x_y x_y_view;
0057
0058 std::vector<views::contour> contours = {range_contour(s_, fs_)};
0059 auto [x_axis, y_axis] = display::view_range(contours);
0060
0061
0062 bool full = (s_._type == proto::surface<point3_container>::e_disc and
0063 s_._opening == std::array<scalar, 2>({-M_PI, M_PI}));
0064
0065 bool draw_axes = true;
0066 if (s_._type == proto::surface<point3_container>::e_disc or
0067 s_._type == proto::surface<point3_container>::e_annulus) {
0068 draw_axes = not fs_;
0069 }
0070
0071 scalar s_x = sh_[0] / (x_axis[1] - x_axis[0]);
0072 scalar s_y = sh_[1] / (y_axis[1] - y_axis[0]);
0073
0074
0075 s_x = s_x < s_y ? s_x : s_y;
0076 s_y = s_y < s_x ? s_y : s_x;
0077
0078
0079 style::transform scale_transform;
0080 scale_transform._scale = {s_x, s_y};
0081
0082
0083 so._summary._scale = scale_transform._scale;
0084
0085
0086 proto::surface<point3_container> draw_surface = s_;
0087 draw_surface._transform._scale = {s_x, s_y};
0088
0089 if (draw_surface._type == decltype(draw_surface)::e_disc) {
0090 draw_surface._vertices.clear();
0091 }
0092
0093
0094 auto surface = display::surface(s_._name + "_in_sheet", draw_surface,
0095 x_y_view, true, true, true, true);
0096 so.add_object(surface);
0097
0098
0099 if (draw_axes) {
0100 display::prepare_axes(x_axis, y_axis, s_x, s_y, 30., 30.);
0101 auto axis_font = __a_font;
0102 axis_font._size = static_cast<scalar>(0.035 * sh_[0]);
0103
0104 so.add_object(draw::x_y_axes(id_ + "_axes_xy", x_axis, y_axis,
0105 __a_stroke, "x", "y", axis_font));
0106 }
0107
0108
0109 style::font m_font = __m_font;
0110 m_font._size = static_cast<scalar>(0.035 * sh_[0]);
0111 style::marker m_marker = __m_marker;
0112 m_marker._size = static_cast<scalar>(0.015 * sh_[0]);
0113
0114
0115 if (s_._type == proto::surface<point3_container>::e_trapez and
0116 s_._measures.size() == 3u) {
0117
0118 scalar hlx_min = s_._measures[0] * s_x;
0119 scalar hlx_max = s_._measures[1] * s_x;
0120 scalar hly = s_._measures[2] * s_y;
0121 scalar ms = 2. * m_marker._size;
0122
0123 std::string h_x_min = "h_x_min";
0124 std::string h_x_max = "h_x_max";
0125 std::string h_y = "h_y";
0126
0127 scalar hly_x = hlx_max + 2 * m_marker._size;
0128
0129 auto measure_hlx_min = draw::measure(
0130 id_ + "_hlx_min", {0, -hly - ms}, {hlx_min, -hly - ms}, __m_stroke,
0131 m_marker, m_marker, m_font,
0132 h_x_min + " = " + utils::to_string(s_._measures[0]),
0133 {static_cast<scalar>(0.5 * hlx_min),
0134 static_cast<scalar>((-hly - ms - 2.2 * m_font._size))});
0135 auto measure_hlx_max = draw::measure(
0136 id_ + "_hlx_max", {0, hly + ms}, {hlx_max, hly + ms}, __m_stroke,
0137 m_marker, m_marker, m_font,
0138 h_x_max + " = " + utils::to_string(s_._measures[1]),
0139 {static_cast<scalar>(0.5 * hlx_max),
0140 static_cast<scalar>(1.2 * m_font._size + (hly + ms))});
0141 auto measure_hly = draw::measure(
0142 id_ + "_hly", {hly_x, 0}, {hly_x, hly}, __m_stroke, m_marker,
0143 m_marker, m_font, h_y + " = " + utils::to_string(s_._measures[2]),
0144 {static_cast<scalar>(m_font._size + hly_x),
0145 static_cast<scalar>(0.5 * hly)});
0146 so.add_object(measure_hlx_min);
0147 so.add_object(measure_hlx_max);
0148 so.add_object(measure_hly);
0149 } else if (s_._type == proto::surface<point3_container>::e_rectangle and
0150 s_._measures.size() == 2u) {
0151
0152 scalar hlx = s_._measures[0] * s_x;
0153 scalar hly = s_._measures[1] * s_y;
0154 scalar ms = 2. * m_marker._size;
0155
0156 std::string h_x = "h_x";
0157 std::string h_y = "h_y";
0158
0159 auto measure_hlx = draw::measure(
0160 id_ + "_hlx", {0, hly + ms}, {hlx, hly + ms}, __m_stroke, m_marker,
0161 m_marker, m_font, h_x + " = " + utils::to_string(s_._measures[0]),
0162 {static_cast<scalar>(0.5 * hlx),
0163 static_cast<scalar>((hly + ms + 1.2 * m_font._size))});
0164 auto measure_hly = draw::measure(
0165 id_ + "_hly", {hlx + ms, 0}, {hlx + ms, hly}, __m_stroke, m_marker,
0166 m_marker, m_font, h_y + " = " + utils::to_string(s_._measures[1]),
0167 {static_cast<scalar>(hlx + 1.2 * m_font._size),
0168 static_cast<scalar>(0.5 * hly)});
0169 so.add_object(measure_hlx);
0170 so.add_object(measure_hly);
0171 } else if (s_._type == proto::surface<point3_container>::e_diamond and
0172 s_._measures.size() == 5u) {
0173
0174 scalar hlx_ymin = s_._measures[0] * s_x;
0175 scalar hlx_y0 = s_._measures[1] * s_x;
0176 scalar hlx_ymax = s_._measures[2] * s_x;
0177 scalar hly_xmin = s_._measures[3] * s_y;
0178 scalar hly_xmax = s_._measures[4] * s_y;
0179 scalar ms = 2. * m_marker._size;
0180
0181
0182 std::string h_x_n = "h_x_ny";
0183 std::string h_x_0 = "h_x_0y";
0184 std::string h_x_p = "h_x_py";
0185 std::string h_y_n = "h_y_nx";
0186 std::string h_y_p = "h_y_px";
0187
0188 auto measure_hlx_ny = draw::measure(
0189 id_ + "_hlx_ny", {0, -hly_xmin - ms}, {hlx_ymin, -hly_xmin - ms},
0190 __m_stroke, m_marker, m_marker, m_font,
0191 h_x_n + " = " + utils::to_string(s_._measures[0]),
0192 {static_cast<scalar>(0.5 * hlx_ymin),
0193 static_cast<scalar>((-hly_xmin - ms - 1.2 * m_font._size))});
0194
0195 auto measure_hlx_0y = draw::measure(
0196 id_ + "_hlx_ny", {0., 0.}, {hlx_y0, 0.}, __m_stroke, m_marker,
0197 m_marker, m_font, h_x_0 + " = " + utils::to_string(s_._measures[1]),
0198 {static_cast<scalar>(0.5 * hlx_y0),
0199 static_cast<scalar>((-ms - 1.2 * m_font._size))});
0200
0201 auto measure_hlx_py = draw::measure(
0202 id_ + "_hlx_py", {0, hly_xmax + ms}, {hlx_ymax, hly_xmax + ms},
0203 __m_stroke, m_marker, m_marker, m_font,
0204 h_x_p + " = " + utils::to_string(s_._measures[2]),
0205 {static_cast<scalar>(0.5 * hlx_ymax),
0206 static_cast<scalar>((hly_xmax + ms + 1.2 * m_font._size))});
0207
0208 auto measure_hly_nx = draw::measure(
0209 id_ + "_hly_nx", {static_cast<scalar>(-0.5 * hlx_ymin), -hly_xmin},
0210 {static_cast<scalar>(-0.5 * hlx_ymin), 0.}, __m_stroke, m_marker,
0211 m_marker, m_font, h_y_n + " = " + utils::to_string(s_._measures[3]),
0212 {static_cast<scalar>(-0.5 * hlx_ymin + ms),
0213 static_cast<scalar>(-0.5 * hly_xmin)});
0214
0215 auto measure_hly_px = draw::measure(
0216 id_ + "_hly_px", {static_cast<scalar>(-0.5 * hlx_ymax), 0.},
0217 {static_cast<scalar>(-0.5 * hlx_ymax), hly_xmax}, __m_stroke,
0218 m_marker, m_marker, m_font,
0219 h_y_p + " = " + utils::to_string(s_._measures[4]),
0220 {static_cast<scalar>(-0.5 * hlx_ymax + ms),
0221 static_cast<scalar>(0.5 * hly_xmax)});
0222
0223 so.add_object(measure_hlx_ny);
0224 so.add_object(measure_hlx_0y);
0225 so.add_object(measure_hlx_py);
0226 so.add_object(measure_hly_nx);
0227 so.add_object(measure_hly_px);
0228
0229 } else if (s_._type == proto::surface<point3_container>::e_polygon and
0230 s_._measures.size() == 2 * s_._vertices.size()) {
0231
0232 point2 gcenter = {0., 0.};
0233
0234 for (unsigned int iv = 0; iv < s_._vertices.size(); ++iv) {
0235 auto v = draw::marker(
0236 id_ + "_vertex_" + std::to_string(iv),
0237 {static_cast<scalar>(s_x * s_._measures[2 * iv]),
0238 static_cast<scalar>(s_y * s_._measures[2 * iv + 1u])},
0239 style::marker({"o"}));
0240
0241 gcenter[0] += s_x * s_._measures[2 * iv];
0242 gcenter[1] += s_y * s_._measures[2 * iv + 1u];
0243
0244 so.add_object(v);
0245 }
0246
0247 gcenter[0] /= s_._vertices.size();
0248 gcenter[1] /= s_._vertices.size();
0249
0250 for (unsigned int iv = 0; iv < s_._vertices.size(); ++iv) {
0251 scalar x = s_x * s_._measures[2 * iv];
0252 scalar y = s_x * s_._measures[2 * iv + 1];
0253
0254 scalar dx = x - gcenter[0];
0255 scalar dy = y - gcenter[1];
0256
0257 scalar dnorm = std::sqrt(dx * dx + dy * dy);
0258 dx /= dnorm;
0259 dy /= dnorm;
0260
0261 std::string label_v = "v" + std::to_string(iv) + " = ";
0262 label_v += utils::to_string(std::array<scalar, 2>{
0263 s_._measures[2 * iv], s_._measures[2 * iv + 1]});
0264
0265 scalar offx = dx > 0 ? 2. * m_font._size * dx
0266 : 0.5 * label_v.size() * m_font._size * dx;
0267 scalar offy = 2 * m_font._size * dy;
0268
0269 so.add_object(draw::text(id_ + "_label_v" + std::to_string(iv),
0270 {x + offx, y + offy}, {label_v}));
0271 }
0272
0273 } else if (s_._type == proto::surface<point3_container>::e_disc and
0274 not s_._measures.empty()) {
0275
0276 std::string dphi = "h_phi";
0277 std::string aphi = "avg_phi";
0278
0279
0280 std::vector<scalar> r_label;
0281 scalar phi_span = 2 * M_PI;
0282
0283 if (full) {
0284 r_label = {M_PI * 0.25, -M_PI * 0.25};
0285 } else {
0286 phi_span = s_._opening[1] - s_._opening[0];
0287 r_label = {static_cast<scalar>(s_._opening[0] - 0.1),
0288 static_cast<scalar>(s_._opening[1] + 0.1)};
0289 }
0290
0291 scalar r_min = std::numeric_limits<scalar>::max();
0292 scalar r_max = 0.;
0293 for (auto [ir, r] : utils::enumerate(s_._measures)) {
0294
0295 std::array<scalar, 2> xs = {
0296 static_cast<scalar>(s_x * r * std::cos(r_label[0])),
0297 static_cast<scalar>(s_x * r * std::cos(r_label[1]))};
0298 std::array<scalar, 2> ys = {
0299 static_cast<scalar>(s_y * r * std::sin(r_label[0])),
0300 static_cast<scalar>(s_y * r * std::sin(r_label[1]))};
0301
0302
0303 if (ir < 2 and
0304 std::abs(r) > std::numeric_limits<scalar>::epsilon()) {
0305
0306 if (not full) {
0307 auto helper_r = draw::arc(id_ + "_arc_helper", s_x * r,
0308 {xs[0], ys[0]}, {xs[1], ys[1]},
0309 style::fill(), __m_stroke_guide);
0310 so.add_object(helper_r);
0311 }
0312
0313
0314 r_max = r > r_max ? r : r_max;
0315 r_min = r < r_min ? r : r_min;
0316 std::string r_o = ir == 0 ? "r" : "R";
0317
0318 scalar rfs = (fs_ and not full) ? s_x * 0.85 * r_min : 0.;
0319 scalar rfs_phi = std::atan2(ys[ir], xs[ir]);
0320
0321 point2 rstart = {static_cast<scalar>(rfs * std::cos(rfs_phi)),
0322 static_cast<scalar>(rfs * std::sin(rfs_phi))};
0323
0324 auto measure_r =
0325 draw::measure(id_ + "_r", rstart, {xs[ir], ys[ir]},
0326 __m_stroke, style::marker(), m_marker, m_font,
0327 r_o + " = " + utils::to_string(r),
0328 {static_cast<scalar>(m_font._size + xs[ir]),
0329 static_cast<scalar>(m_font._size + ys[ir])});
0330 so.add_object(measure_r);
0331 }
0332
0333 if (ir == 2 and not full) {
0334
0335
0336 scalar rfs = (fs_ and not full) ? s_x * 0.85 * r_min : 0.;
0337
0338
0339 scalar lr = s_x * r_max + 2. * m_marker._size;
0340
0341 point2 start = {
0342 static_cast<scalar>(lr * std::cos(s_._opening[0])),
0343 static_cast<scalar>(lr * std::sin(s_._opening[0]))};
0344
0345
0346 scalar mphi = 0.5 * (s_._opening[0] + s_._opening[1]);
0347 point2 end = {static_cast<scalar>(lr * std::cos(mphi)),
0348 static_cast<scalar>(lr * std::sin(mphi))};
0349
0350 scalar mmphi = 0.5 * (s_._opening[0] + mphi);
0351 point2 mend = {
0352 static_cast<scalar>(m_font._size + lr * std::cos(mmphi)),
0353 static_cast<scalar>(m_font._size + lr * std::sin(mmphi))};
0354
0355 auto maesure_arc = draw::arc_measure(
0356 id_ + "_arc", lr, start, end, __m_stroke, m_marker,
0357 m_marker, m_font, dphi + " = " + utils::to_string(phi_span),
0358 mend);
0359
0360 so.add_object(maesure_arc);
0361
0362 point2 mstart = {static_cast<scalar>(rfs * std::cos(mphi)),
0363 static_cast<scalar>(rfs * std::sin(mphi))};
0364
0365 auto medium_phi_line = draw::line(id_ + "medium_phi", mstart,
0366 end, __m_stroke_guide);
0367 so.add_object(medium_phi_line);
0368
0369
0370 scalar r_avg_phi = 0.2 * s_x * r_max;
0371 std::array<scalar, 2> r_avg_start = {r_avg_phi, 0.};
0372 std::array<scalar, 2> r_avg_end = {
0373 static_cast<scalar>(r_avg_phi * std::cos(mphi)),
0374 static_cast<scalar>(r_avg_phi * std::sin(mphi))};
0375
0376 std::array<scalar, 2> r_avg_mend = {
0377 static_cast<scalar>(m_font._size +
0378 r_avg_phi * std::cos(0.5 * mphi)),
0379 static_cast<scalar>(m_font._size +
0380 r_avg_phi * std::sin(0.5 * mphi))};
0381
0382 if (std::abs(mphi) >
0383 5 * std::numeric_limits<scalar>::epsilon()) {
0384 auto measure_avg_phi = draw::arc_measure(
0385 id_ + "_avg_phi", r_avg_phi, r_avg_start, r_avg_end,
0386 __m_stroke, style::marker(), m_marker, m_font,
0387 aphi + " = " + utils::to_string(mphi), r_avg_mend);
0388 so.add_object(measure_avg_phi);
0389 }
0390 }
0391 }
0392 } else if (s_._type == proto::surface<point3_container>::e_annulus and
0393 not s_._measures.empty()) {
0394
0395 if (s_._measures.size() != 7u) {
0396 throw std::invalid_argument(
0397 "surface_sheet_xy(...) - incorrect length of <measures> for "
0398 "annulus shape.");
0399 }
0400
0401
0402 scalar min_r = s_x * s_._measures[0];
0403 scalar max_r = s_x * s_._measures[1];
0404 scalar min_phi_rel = s_._measures[2];
0405 scalar max_phi_rel = s_._measures[3];
0406
0407 scalar origin_x = s_x * s_._measures[5];
0408 scalar origin_y = s_x * s_._measures[6];
0409
0410 point2 cart_origin = {origin_x, origin_y};
0411
0412
0413
0414
0415
0416
0417 auto circIx = [](scalar O_x, scalar O_y, scalar r,
0418 scalar phi) -> point2 {
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429 scalar m = std::tan(phi);
0430 point2 dir = {std::cos(phi), std::sin(phi)};
0431 scalar x1 =
0432 (O_x + O_y * m -
0433 std::sqrt(-std::pow(O_x, 2) * std::pow(m, 2) +
0434 2 * O_x * O_y * m - std::pow(O_y, 2) +
0435 std::pow(m, 2) * std::pow(r, 2) + std::pow(r, 2))) /
0436 (std::pow(m, 2) + 1);
0437 scalar x2 =
0438 (O_x + O_y * m +
0439 std::sqrt(-std::pow(O_x, 2) * std::pow(m, 2) +
0440 2 * O_x * O_y * m - std::pow(O_y, 2) +
0441 std::pow(m, 2) * std::pow(r, 2) + std::pow(r, 2))) /
0442 (std::pow(m, 2) + 1);
0443
0444 point2 v1 = {x1, m * x1};
0445 if (v1[0] * dir[0] + v1[1] * dir[1] > 0) {
0446 return v1;
0447 }
0448 return {x2, m * x2};
0449 };
0450
0451 auto out_left_s_xy = circIx(origin_x, origin_y, max_r, max_phi_rel);
0452 auto in_left_s_xy = circIx(origin_x, origin_y, min_r, max_phi_rel);
0453 auto out_right_s_xy = circIx(origin_x, origin_y, max_r, min_phi_rel);
0454 auto in_right_s_xy = circIx(origin_x, origin_y, min_r, min_phi_rel);
0455
0456 std::vector<point2> corners = {in_right_s_xy, in_left_s_xy,
0457 out_right_s_xy, out_left_s_xy};
0458
0459 so.add_object(draw::line(id_ + "_phi_line_l", {0, 0}, in_left_s_xy,
0460 __m_stroke_guide));
0461
0462 so.add_object(draw::line(id_ + "_phi_line_r", {0, 0}, in_right_s_xy,
0463 __m_stroke_guide));
0464
0465 std::vector<std::string> phi_labels = {"phi_min_rel", "phi_max_rel"};
0466
0467 for (unsigned int ic = 0; ic < 2; ++ic) {
0468
0469 const auto& corner = corners[ic];
0470 scalar in_phi = atan2(corner[1], corner[0]);
0471
0472 scalar in_r = (0.2 + ic * 0.2) * utils::perp(corners[ic]);
0473 std::array<scalar, 2> in_start = {in_r, 0.};
0474 std::array<scalar, 2> in_end = {
0475 static_cast<scalar>(in_r * std::cos(in_phi)),
0476 static_cast<scalar>(in_r * std::sin(in_phi))};
0477
0478 std::array<scalar, 2> in_mend = {
0479 static_cast<scalar>(m_font._size +
0480 in_r * std::cos(0.5 * in_phi)),
0481 static_cast<scalar>(m_font._size +
0482 in_r * std::sin(0.5 * in_phi))};
0483
0484 auto in_phi_arc = draw::arc_measure(
0485 id_ + "_in_phi_" + std::to_string(ic), in_r, in_start, in_end,
0486 __m_stroke, style::marker(), m_marker, m_font,
0487 phi_labels[ic] + " = " + utils::to_string(in_phi), in_mend);
0488 so.add_object(in_phi_arc);
0489 }
0490
0491 style::marker cart_origin_marker = style::marker({"o"});
0492 cart_origin_marker._fill = style::fill(style::color{{255, 0, 0}});
0493
0494 style::font cart_font = m_font;
0495 cart_font._fc = style::color{{255, 0, 0}};
0496
0497 style::stroke cart_stroke = __m_stroke;
0498 cart_stroke._sc = style::color{{255, 0, 0}};
0499
0500 style::marker cart_marker = m_marker;
0501 cart_marker._fill = style::fill(style::color{{255, 0, 0}});
0502 cart_marker._stroke = cart_stroke;
0503
0504
0505 so.add_object(draw::marker(id_ + "_origin_cart", {origin_x, origin_y},
0506 cart_origin_marker));
0507
0508 so.add_object(draw::text(
0509 id_ + "_origin_label",
0510 {origin_x - 2 * cart_font._size, origin_y - 2 * cart_font._size},
0511 {"cart_origin = " + utils::to_string(std::array<scalar, 2>{
0512 s_._measures[5], s_._measures[6]})},
0513 cart_font));
0514
0515 style::stroke cart_guide = __m_stroke_guide;
0516 cart_guide._sc = style::color{{255, 0, 0}};
0517
0518 std::vector<std::string> rs = {"r", "R"};
0519
0520 for (unsigned int idc = 0; idc < 2; ++idc) {
0521
0522 const auto& c0 = corners[2 * idc];
0523 const auto& c1 = corners[2 * idc + 1];
0524
0525 point2 cart_c0 = point2{c0[0] - origin_x, c0[1] - origin_y};
0526 point2 cart_c1 = point2{c1[0] - origin_x, c1[1] - origin_y};
0527 scalar cart_r = utils::perp(cart_c0);
0528
0529 scalar cart_phi0 = atan2(cart_c0[1], cart_c0[0]) - 0.2;
0530 scalar cart_phi1 = atan2(cart_c1[1], cart_c1[0]) + 0.25;
0531 scalar cart_phir = cart_phi1 - (2 * idc + 1) * 0.05;
0532
0533 point2 start_arc = {
0534 static_cast<scalar>(origin_x + cart_r * std::cos(cart_phi0)),
0535 static_cast<scalar>(origin_y + cart_r * std::sin(cart_phi0))};
0536 point2 end_arc = {
0537 static_cast<scalar>(origin_x + cart_r * std::cos(cart_phi1)),
0538 static_cast<scalar>(origin_y + cart_r * std::sin(cart_phi1))};
0539
0540 point2 end_r = {
0541 static_cast<scalar>(origin_x + cart_r * std::cos(cart_phir)),
0542 static_cast<scalar>(origin_y + cart_r * std::sin(cart_phir))};
0543
0544 auto helper_r =
0545 draw::arc(id_ + "_arc_helper_" + std::to_string(idc), cart_r,
0546 start_arc, end_arc, style::fill(), cart_guide);
0547 so.add_object(helper_r);
0548
0549 auto measure_r = draw::measure(
0550 id_ + "_measure_r_" + std::to_string(idc), cart_origin, end_r,
0551 cart_stroke, style::marker(), cart_marker, cart_font,
0552 rs[idc] + " = " +
0553 utils::to_string(static_cast<scalar>(cart_r / s_x)),
0554 {static_cast<scalar>(m_font._size + end_r[0]),
0555 static_cast<scalar>(m_font._size + end_r[1])});
0556 so.add_object(measure_r);
0557 }
0558 }
0559 return so;
0560 }
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573 template <typename point3_container, typename view_type, layer_type lT>
0574 svg::object sheet(const std::string& id_,
0575 const proto::volume<point3_container>& v_,
0576 const std::array<scalar, 2>& sh_ = {600., 600.},
0577 sheet_type t_ = e_module_info,
0578 const std::array<scalar, 2>& s_sh_ = {600., 600.}) {
0579
0580 svg::object o_sheet;
0581 o_sheet._tag = "g";
0582 o_sheet._id = id_;
0583
0584 view_type view;
0585
0586 scalar sub_offset = 0.25;
0587
0588
0589 auto [modules, scale_transform, axes] = process_modules(
0590 v_, view, sh_, lT == e_endcap, t_ == e_module_info, lT == e_endcap);
0591 auto x_axis = axes[0];
0592 auto y_axis = axes[1];
0593
0594
0595 o_sheet._summary._scale = scale_transform._scale;
0596
0597
0598 for (auto [ib, surface_batch] : utils::enumerate(v_._surfaces)) {
0599 for (auto [is, s] : utils::enumerate(surface_batch)) {
0600 auto& m = modules[ib][is];
0601 if (t_ == e_module_info and
0602 s._aux_info.find("module_info") != s._aux_info.end()) {
0603 m._aux_info = s._aux_info.find("module_info")->second;
0604 } else if (t_ == e_grid_info and
0605 s._aux_info.find("grid_info") != s._aux_info.end()) {
0606 m._aux_info = s._aux_info.find("grid_info")->second;
0607 }
0608 }
0609 }
0610
0611
0612 std::vector<svg::object> extra_objects;
0613
0614 std::vector<std::vector<svg::object>> all_s_sheets;
0615
0616
0617 if (t_ == e_module_info) {
0618
0619 for (auto [ib, surface_batch] : utils::enumerate(v_._surfaces)) {
0620 std::vector<svg::object> s_sheets;
0621 for (auto s : surface_batch) {
0622
0623 style::fill s_fill;
0624 s_fill._fc._rgb = s._fill._fc._hl_rgb;
0625 s_fill._fc._opacity = s._fill._fc._opacity;
0626 s._fill = s_fill;
0627
0628 svg::object s_sheet;
0629 s_sheet._id = s._name + "_surface_sheet";
0630 s_sheet._tag = "g";
0631
0632 auto bg_panel =
0633 draw::rectangle(s._name + "_surface_sheet_bg", {0, 0},
0634 static_cast<scalar>(0.7 * s_sh_[0]),
0635 static_cast<scalar>(0.7 * s_sh_[1]),
0636 __bg_fill, __bg_stroke);
0637 s_sheet.add_object(bg_panel);
0638 s_sheet.add_object(display::surface_sheet_xy(
0639 s._name + "_surface_sheet_display", s, s_sh_,
0640 lT == e_endcap));
0641
0642 style::transform(
0643 {{static_cast<scalar>((ib + 1) *
0644 (sh_[0] + sub_offset * s_sh_[0])),
0645 0., 0.}})
0646 .attach_attributes(s_sheet);
0647 s_sheets.push_back(s_sheet);
0648 }
0649 all_s_sheets.push_back(s_sheets);
0650 }
0651 } else if (t_ == e_grid_info and not v_._surface_grid._edges_0.empty() and
0652 not v_._surface_grid._edges_1.empty()) {
0653
0654 svg::object sub_sheet;
0655
0656 if (lT == e_endcap) {
0657 extra_objects =
0658 draw::tiled_polar_grid(id_, v_._surface_grid._edges_0,
0659 v_._surface_grid._edges_1, __g_fill,
0660 __g_stroke, scale_transform)
0661 ._sub_objects;
0662 } else if (lT == e_barrel) {
0663 extra_objects =
0664 draw::tiled_cartesian_grid(id_, v_._surface_grid._edges_0,
0665 v_._surface_grid._edges_1, __g_fill,
0666 __g_stroke, scale_transform)
0667 ._sub_objects;
0668 }
0669
0670
0671 for (auto [ib, module_batch] : utils::enumerate(modules)) {
0672
0673 style::font info_font;
0674 info_font._size = static_cast<unsigned int>(0.03 * s_sh_[0]);
0675 auto c_objects = connectors::connect_action(
0676 extra_objects, module_batch, v_._grid_associations[ib], ib == 0u,
0677 {"mouseover", "mouseout"},
0678 {connectors::e_highlight, connectors::e_associate_info},
0679 info_font);
0680 scalar offsx =
0681 static_cast<scalar>((ib * (1 + sub_offset) + 0.7) * sh_[0]);
0682 scalar offsy = std::abs(0.1 * y_axis[1]);
0683
0684 std::for_each(
0685 c_objects.begin(), c_objects.end(), [&](svg::object& o_) {
0686 o_._attribute_map["x"] = utils::to_string(offsx);
0687 o_._attribute_map["y"] = utils::to_string(offsy);
0688 o_._x_range = {static_cast<scalar>(offsx - 100.), offsy};
0689 });
0690 o_sheet.add_objects(c_objects);
0691 }
0692 }
0693
0694
0695 for (auto [ib, module_batch] : utils::enumerate(modules)) {
0696
0697 svg::object sub_sheet;
0698 sub_sheet._tag = "g";
0699 sub_sheet._id = id_ + "_sub_sheet_" + std::to_string(ib);
0700 sub_sheet.add_objects(module_batch);
0701
0702 auto axis_font = __a_font;
0703 axis_font._size = static_cast<unsigned int>(0.035 * s_sh_[0]);
0704 sub_sheet.add_object(draw::x_y_axes(id_ + "_xy", x_axis, y_axis,
0705 __a_stroke, view._axis_names[0],
0706 view._axis_names[1], axis_font));
0707
0708 style::transform(
0709 {{static_cast<scalar>(ib * (sh_[0] + sub_offset * s_sh_[0])), 0.,
0710 0.}})
0711 .attach_attributes(sub_sheet);
0712
0713 o_sheet.add_object(sub_sheet);
0714 }
0715
0716
0717 if (not all_s_sheets.empty()) {
0718
0719 connect_surface_sheets(v_, all_s_sheets, o_sheet);
0720 }
0721
0722
0723 if (not extra_objects.empty()) {
0724 o_sheet.add_objects(extra_objects);
0725 }
0726
0727
0728 auto title_font = __t_font;
0729 title_font._size = 0.05 * sh_[0];
0730 auto title = draw::text(id_ + "sheet_title",
0731 {static_cast<scalar>(-0.55 * sh_[0]),
0732 static_cast<scalar>(0.6 * sh_[1])},
0733 {v_._name}, title_font);
0734 o_sheet.add_object(title);
0735
0736 return o_sheet;
0737 }
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749 template <typename point3_container>
0750 svg::object endcap_sheet(const std::string& id_,
0751 const proto::volume<point3_container>& v_,
0752 const std::array<scalar, 2>& sh_ = {600., 600.},
0753 sheet_type t_ = e_module_info,
0754 const std::array<scalar, 2>& s_sh_ = {600., 600.}) {
0755
0756 return sheet<point3_container, views::x_y, e_endcap>(id_, v_, sh_, t_,
0757 s_sh_);
0758 }
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770 template <typename point3_container>
0771 svg::object barrel_sheet(const std::string& id_,
0772 const proto::volume<point3_container>& v_,
0773 const std::array<scalar, 2>& sh_ = {600., 600.},
0774 sheet_type t_ = e_module_info,
0775 const std::array<scalar, 2>& s_sh_ = {600., 600.}) {
0776
0777 return sheet<point3_container, views::z_phi, e_barrel>(id_, v_, sh_, t_,
0778 s_sh_);
0779 }
0780
0781 }
0782 }