File indexing completed on 2025-12-25 09:17:52
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <string>
0012 #include <vector>
0013
0014 #include "actsvg/core.hpp"
0015 #include "actsvg/display/geometry.hpp"
0016 #include "actsvg/proto/surface.hpp"
0017 #include "actsvg/proto/volume.hpp"
0018 #include "actsvg/styles/defaults.hpp"
0019
0020 namespace actsvg {
0021
0022 using namespace defaults;
0023
0024 namespace display {
0025
0026
0027
0028
0029
0030
0031
0032 template <typename point3_container>
0033 std::string center_string(const point3_container& vs) {
0034 std::string c_str = "center = (";
0035 scalar c_x = 0;
0036 scalar c_y = 0;
0037 scalar c_z = 0;
0038 for (auto& v : vs) {
0039 c_x += v[0];
0040 c_y += v[1];
0041 c_z += v[2];
0042 }
0043 c_x /= vs.size();
0044 c_y /= vs.size();
0045 c_z /= vs.size();
0046 return c_str + std::to_string(c_x) + "," + std::to_string(c_y) + ", " +
0047 std::to_string(c_z) + ")";
0048 }
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 void prepare_axes(std::array<scalar, 2>& first_, std::array<scalar, 2>& second_,
0062 scalar sx_, scalar sy_, scalar ax_ = 0., scalar ay_ = 0.);
0063
0064
0065
0066
0067
0068
0069
0070
0071 template <typename surface_type, typename view_type = views::x_y>
0072 views::contour range_contour(const surface_type& s_,
0073 bool fs_ = false) noexcept(false) {
0074
0075 view_type view;
0076
0077 using point3 = typename surface_type::point3_type;
0078
0079
0080 views::contour contour;
0081 if (s_._template_object.is_defined()) {
0082
0083
0084 point2 bbl = {s_._template_object._x_range[0],
0085 s_._template_object._y_range[0]};
0086 point2 bbr = {s_._template_object._x_range[1],
0087 s_._template_object._y_range[1]};
0088 if (not fs_) {
0089 bbl[0] += s_._transform._tr[0];
0090 bbl[1] += s_._transform._tr[1];
0091 bbr[0] += s_._transform._tr[0];
0092 bbr[1] += s_._transform._tr[1];
0093 scalar alpha = s_._transform._rot[0];
0094 if (alpha != 0.) {
0095 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0096 bbl = utils::rotate(bbl, alpha_rad);
0097 bbr = utils::rotate(bbr, alpha_rad);
0098 }
0099 }
0100 contour = {bbl, bbr};
0101 } else if (not s_._vertices.empty()) {
0102
0103 contour = view.path(s_._vertices);
0104 if (not fs_) {
0105 std::for_each(contour.begin(), contour.end(), [&](auto& v) {
0106 scalar alpha = s_._transform._rot[0];
0107 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0108 v = utils::rotate(v, alpha_rad);
0109 v[0] += s_._transform._tr[0];
0110 v[1] += s_._transform._tr[1];
0111 });
0112 }
0113 } else if (s_._radii[1] != 0.) {
0114
0115 scalar ri = s_._radii[0];
0116 scalar ro = s_._radii[1];
0117 scalar phi_low = s_._opening[0];
0118 scalar phi_high = s_._opening[1];
0119 scalar phi = 0.5_scalar * (phi_low + phi_high);
0120 scalar cos_phi_low = std::cos(phi_low);
0121 scalar sin_phi_low = std::sin(phi_low);
0122 scalar cos_phi_high = std::cos(phi_high);
0123 scalar sin_phi_high = std::cos(phi_high);
0124
0125 point3 A = {ri * cos_phi_low, ri * sin_phi_low, 0.};
0126 point3 B = {ri * std::cos(phi), ri * std::sin(phi), 0.};
0127 point3 C = {ri * cos_phi_high, ri * sin_phi_high, 0.};
0128 point3 D = {ro * cos_phi_high, ro * sin_phi_high, 0.};
0129 point3 E = {ro * std::cos(phi), ro * std::sin(phi), 0.};
0130 point3 F = {ro * cos_phi_low, ro * sin_phi_low, 0.};
0131
0132 std::vector<point3> vertices_disc = {A, B, C, D, E, F};
0133 contour = view.path(vertices_disc);
0134 } else {
0135 throw std::invalid_argument(
0136 "surface_sheet_xy(...) - could not estimate range.");
0137 }
0138 return contour;
0139 }
0140
0141
0142
0143
0144
0145
0146
0147 template <typename contour_container>
0148 static std::array<std::array<scalar, 2>, 2> view_range(
0149 const contour_container& cc_) {
0150
0151 std::array<scalar, 2> x_range = __e_object._x_range;
0152 std::array<scalar, 2> y_range = __e_object._y_range;
0153
0154 for (auto& c : cc_) {
0155 for (auto& v : c) {
0156 x_range[0] = std::min(v[0], x_range[0]);
0157 x_range[1] = std::max(v[0], x_range[1]);
0158 y_range[0] = std::min(v[1], y_range[0]);
0159 y_range[1] = std::max(v[1], y_range[1]);
0160 }
0161 }
0162 return {x_range, y_range};
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 template <typename volume_type, typename view_type>
0177 std::tuple<std::vector<std::vector<svg::object>>, style::transform,
0178 std::array<std::array<scalar, 2>, 2>>
0179 process_modules(const volume_type& v_, const view_type& view_,
0180 const std::array<scalar, 2>& sh_ = {600., 600.},
0181 bool es_ = false, bool hl_ = true, bool dt_ = true) {
0182
0183 using surface_type = typename volume_type::surface_type;
0184
0185
0186 std::vector<std::vector<views::contour>> all_contours;
0187 for (const auto& surfaces : v_._surfaces) {
0188 std::vector<views::contour> contours;
0189 contours.reserve(surfaces.size());
0190 for (const auto& s : surfaces) {
0191 surface_type range_surface = s;
0192 if (not dt_) {
0193 range_surface._template_object = svg::object{};
0194 }
0195 contours.push_back(
0196 range_contour<surface_type, view_type>(range_surface));
0197 }
0198 all_contours.push_back(contours);
0199 }
0200
0201
0202 std::vector<views::contour> flattened_contours;
0203 for (const auto& c : all_contours) {
0204 flattened_contours.insert(flattened_contours.end(), c.begin(), c.end());
0205 }
0206
0207
0208 auto axes = display::view_range(flattened_contours);
0209
0210 scalar s_x = sh_[0] / (axes[0][1] - axes[0][0]);
0211 scalar s_y = sh_[1] / (axes[1][1] - axes[1][0]);
0212
0213 if (es_) {
0214
0215 s_x = s_x < s_y ? s_x : s_y;
0216 s_y = s_y < s_x ? s_y : s_x;
0217 }
0218
0219
0220 style::transform scale_transform;
0221 scale_transform._scale = {s_x, s_y};
0222
0223
0224 std::vector<std::vector<svg::object>> all_modules;
0225 for (auto [ics, contours] : utils::enumerate(all_contours)) {
0226 std::vector<svg::object> modules;
0227 modules.reserve(contours.size());
0228 for (auto [ic, c] : utils::enumerate(contours)) {
0229 surface_type draw_surface = v_._surfaces[ics][ic];
0230 draw_surface._transform._scale = {s_x, s_y};
0231 if (not hl_) {
0232 draw_surface._fill._fc._highlight = {};
0233 }
0234 if (not dt_) {
0235 draw_surface._template_object = svg::object{};
0236 }
0237
0238 auto surface_module =
0239 display::surface(draw_surface._name, draw_surface, view_,
0240 {true, false, true, false});
0241 modules.push_back(surface_module);
0242 }
0243 all_modules.push_back(modules);
0244 }
0245
0246
0247 prepare_axes(axes[0], axes[1], s_x, s_y, 30., 30.);
0248
0249 return {all_modules, scale_transform, axes};
0250 }
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 template <typename volume_type>
0263 void connect_surface_sheets(const volume_type& v_,
0264 std::vector<std::vector<svg::object>>& templates_,
0265 svg::object& o_) {
0266
0267 for (auto [ib, surface_batch] : utils::enumerate(v_._surfaces)) {
0268 for (auto [is, s] : utils::enumerate(surface_batch)) {
0269 std::string sid = s._name;
0270
0271 svg::object& s_sheet_s = templates_[ib][is];
0272 s_sheet_s._attribute_map["display"] = "none";
0273
0274
0275 svg::object on;
0276 on._tag = "animate";
0277 on._attribute_map["fill"] = "freeze";
0278 on._attribute_map["attributeName"] = "display";
0279 on._attribute_map["from"] = "none";
0280 on._attribute_map["to"] = "block";
0281 on._attribute_map["begin"] = sid + __d + "mouseout";
0282
0283 svg::object off;
0284
0285 off._tag = "animate";
0286 off._attribute_map["fill"] = "freeze";
0287 off._attribute_map["attributeName"] = "display";
0288 off._attribute_map["to"] = "none";
0289 off._attribute_map["from"] = "block";
0290 off._attribute_map["begin"] = sid + __d + "mouseover";
0291
0292
0293 s_sheet_s._sub_objects.push_back(off);
0294 s_sheet_s._sub_objects.push_back(on);
0295
0296 o_.add_object(s_sheet_s);
0297 }
0298 }
0299 }
0300
0301 }
0302
0303 }