File indexing completed on 2025-01-18 09:28:07
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 static inline void prepare_axes(std::array<scalar, 2>& first_,
0062 std::array<scalar, 2>& second_, scalar sx_,
0063 scalar sy_, scalar ax_ = 0., scalar ay_ = 0.) {
0064
0065 first_[0] *= sx_;
0066 first_[1] *= sx_;
0067 first_[0] -= ax_;
0068 first_[1] += ax_;
0069
0070 second_[0] *= sy_;
0071 second_[1] *= sy_;
0072 second_[0] -= ay_;
0073 second_[1] += ay_;
0074 }
0075
0076
0077
0078
0079
0080
0081
0082
0083 template <typename surface_type, typename view_type = views::x_y>
0084 views::contour range_contour(const surface_type& s_,
0085 bool fs_ = false) noexcept(false) {
0086
0087 view_type view;
0088
0089 using point3 = typename surface_type::point3_type;
0090
0091
0092 views::contour contour;
0093 if (s_._template_object.is_defined()) {
0094
0095
0096 point2 bbl = {s_._template_object._x_range[0],
0097 s_._template_object._y_range[0]};
0098 point2 bbr = {s_._template_object._x_range[1],
0099 s_._template_object._y_range[1]};
0100 if (not fs_) {
0101 bbl[0] += s_._transform._tr[0];
0102 bbl[1] += s_._transform._tr[1];
0103 bbr[0] += s_._transform._tr[0];
0104 bbr[1] += s_._transform._tr[1];
0105 scalar alpha = s_._transform._rot[0];
0106 if (alpha != 0.) {
0107 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0108 bbl = utils::rotate(bbl, alpha_rad);
0109 bbr = utils::rotate(bbr, alpha_rad);
0110 }
0111 }
0112 contour = {bbl, bbr};
0113 } else if (not s_._vertices.empty()) {
0114
0115 contour = view(s_._vertices);
0116 if (not fs_) {
0117 std::for_each(contour.begin(), contour.end(), [&](auto& v) {
0118 scalar alpha = s_._transform._rot[0];
0119 scalar alpha_rad = static_cast<scalar>(alpha / M_PI * 180.);
0120 v = utils::rotate(v, alpha_rad);
0121 v[0] += s_._transform._tr[0];
0122 v[1] += s_._transform._tr[1];
0123 });
0124 }
0125 } else if (s_._radii[1] != 0.) {
0126
0127 scalar ri = s_._radii[0];
0128 scalar ro = s_._radii[1];
0129 scalar phi_low = s_._opening[0];
0130 scalar phi_high = s_._opening[1];
0131 scalar phi = 0.5 * (phi_low + phi_high);
0132 scalar cos_phi_low = std::cos(phi_low);
0133 scalar sin_phi_low = std::sin(phi_low);
0134 scalar cos_phi_high = std::cos(phi_high);
0135 scalar sin_phi_high = std::cos(phi_high);
0136
0137 point3 A = {ri * cos_phi_low, ri * sin_phi_low, 0.};
0138 point3 B = {ri * std::cos(phi), ri * std::sin(phi), 0.};
0139 point3 C = {ri * cos_phi_high, ri * sin_phi_high, 0.};
0140 point3 D = {ro * cos_phi_high, ro * sin_phi_high, 0.};
0141 point3 E = {ro * std::cos(phi), ro * std::sin(phi), 0.};
0142 point3 F = {ro * cos_phi_low, ro * sin_phi_low, 0.};
0143
0144 std::vector<point3> vertices_disc = {A, B, C, D, E, F};
0145 contour = view(vertices_disc);
0146 } else {
0147 throw std::invalid_argument(
0148 "surface_sheet_xy(...) - could not estimate range.");
0149 }
0150 return contour;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159 template <typename contour_container>
0160 static std::array<std::array<scalar, 2>, 2> view_range(
0161 const contour_container& cc_) {
0162
0163 std::array<scalar, 2> x_range = __e_object._x_range;
0164 std::array<scalar, 2> y_range = __e_object._y_range;
0165
0166 for (auto& c : cc_) {
0167 for (auto& v : c) {
0168 x_range[0] = std::min(v[0], x_range[0]);
0169 x_range[1] = std::max(v[0], x_range[1]);
0170 y_range[0] = std::min(v[1], y_range[0]);
0171 y_range[1] = std::max(v[1], y_range[1]);
0172 }
0173 }
0174 return {x_range, y_range};
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 template <typename volume_type, typename view_type>
0189 std::tuple<std::vector<std::vector<svg::object>>, style::transform,
0190 std::array<std::array<scalar, 2>, 2>>
0191 process_modules(const volume_type& v_, const view_type& view_,
0192 const std::array<scalar, 2>& sh_ = {600., 600.},
0193 bool es_ = false, bool hl_ = true, bool dt_ = true) {
0194
0195 using surface_type = typename volume_type::surface_type;
0196
0197
0198 std::vector<std::vector<views::contour>> all_contours;
0199 for (const auto& surfaces : v_._surfaces) {
0200 std::vector<views::contour> contours;
0201 contours.reserve(surfaces.size());
0202 for (const auto& s : surfaces) {
0203 surface_type range_surface = s;
0204 if (not dt_) {
0205 range_surface._template_object = svg::object{};
0206 }
0207 contours.push_back(
0208 range_contour<surface_type, view_type>(range_surface));
0209 }
0210 all_contours.push_back(contours);
0211 }
0212
0213
0214 std::vector<views::contour> flattened_contours;
0215 for (const auto& c : all_contours) {
0216 flattened_contours.insert(flattened_contours.end(), c.begin(), c.end());
0217 }
0218
0219
0220 auto axes = display::view_range(flattened_contours);
0221
0222 scalar s_x = sh_[0] / (axes[0][1] - axes[0][0]);
0223 scalar s_y = sh_[1] / (axes[1][1] - axes[1][0]);
0224
0225 if (es_) {
0226
0227 s_x = s_x < s_y ? s_x : s_y;
0228 s_y = s_y < s_x ? s_y : s_x;
0229 }
0230
0231
0232 style::transform scale_transform;
0233 scale_transform._scale = {s_x, s_y};
0234
0235
0236 std::vector<std::vector<svg::object>> all_modules;
0237 for (auto [ics, contours] : utils::enumerate(all_contours)) {
0238 std::vector<svg::object> modules;
0239 modules.reserve(contours.size());
0240 for (auto [ic, c] : utils::enumerate(contours)) {
0241 surface_type draw_surface = v_._surfaces[ics][ic];
0242 draw_surface._transform._scale = {s_x, s_y};
0243 if (not hl_) {
0244 draw_surface._fill._fc._highlight = {};
0245 }
0246 if (not dt_) {
0247 draw_surface._template_object = svg::object{};
0248 }
0249
0250 auto surface_module =
0251 display::surface(draw_surface._name, draw_surface, view_, true,
0252 false, true, false);
0253 modules.push_back(surface_module);
0254 }
0255 all_modules.push_back(modules);
0256 }
0257
0258
0259 prepare_axes(axes[0], axes[1], s_x, s_y, 30., 30.);
0260
0261 return {all_modules, scale_transform, axes};
0262 }
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 template <typename volume_type>
0275 void connect_surface_sheets(const volume_type& v_,
0276 std::vector<std::vector<svg::object>>& templates_,
0277 svg::object& o_) {
0278
0279 for (auto [ib, surface_batch] : utils::enumerate(v_._surfaces)) {
0280 for (auto [is, s] : utils::enumerate(surface_batch)) {
0281 std::string sid = s._name;
0282
0283 svg::object& s_sheet_s = templates_[ib][is];
0284 s_sheet_s._attribute_map["display"] = "none";
0285
0286
0287 svg::object on;
0288 on._tag = "animate";
0289 on._attribute_map["fill"] = "freeze";
0290 on._attribute_map["attributeName"] = "display";
0291 on._attribute_map["from"] = "none";
0292 on._attribute_map["to"] = "block";
0293 on._attribute_map["begin"] = sid + __d + "mouseout";
0294
0295 svg::object off;
0296
0297 off._tag = "animate";
0298 off._attribute_map["fill"] = "freeze";
0299 off._attribute_map["attributeName"] = "display";
0300 off._attribute_map["to"] = "none";
0301 off._attribute_map["from"] = "block";
0302 off._attribute_map["begin"] = sid + __d + "mouseover";
0303
0304
0305 s_sheet_s._sub_objects.push_back(off);
0306 s_sheet_s._sub_objects.push_back(on);
0307
0308 o_.add_object(s_sheet_s);
0309 }
0310 }
0311 }
0312
0313 }
0314
0315 }