1#ifndef TATOOINE_GEOMETRY_HYPER_ELLIPSE_H
2#define TATOOINE_GEOMETRY_HYPER_ELLIPSE_H
12template <
floating_po
int Real, std::
size_t NumDimensions>
struct hyper_ellipse {
13 static_assert(NumDimensions > 1);
60 requires(
sizeof...(radii) > 0)
62 static_assert(
sizeof...(radii) == NumDimensions,
63 "Number of radii does not match number of dimensions.");
68 requires(
sizeof...(radii) > 1)
71 static_assert(
sizeof...(radii) == NumDimensions,
72 "Number of radii does not match number of dimensions.");
77 requires(
sizeof...(points) == NumDimensions)
88 auto S() const -> auto const & {
return m_S; }
89 auto S() ->
auto & {
return m_S; }
120 auto const local_distance_to_point = euclidian_length(x_local);
121 auto const local_point_on_boundary = x_local / local_distance_to_point;
122 auto const local_offset_to_boundary = x_local - local_point_on_boundary;
123 return euclidian_length(
m_S * local_offset_to_boundary);
128 return local_point_on_boundary;
138 template <std::size_t... Is>
139 constexpr auto fit(std::index_sequence<Is...> ,
142 ([&] { H.col(Is) = points; }(), ...);
150 static_assert(
sizeof...(points) == NumDimensions,
151 "Number of points does not match number of dimensions.");
152 fit(std::make_index_sequence<NumDimensions>{}, points...);
165 template <
typename V,
typename VReal>
179 requires(NumDimensions == 2)
181 using namespace std::ranges;
186 auto radian_to_cartesian = [](
auto const t) {
187 return vec{std::cos(t), std::sin(t)};
189 auto out_it = std::back_inserter(discretization);
190 copy(radial | views::transform(radian_to_cartesian), out_it);
191 discretization.set_closed(
true);
192 for (
auto const v : discretization.vertices()) {
193 discretization[v] =
S() * discretization[v] +
center();
195 return discretization;
198 auto discretize(std::size_t
const num_subdivisions = 2) const
199 requires(NumDimensions == 3)
203 using edge = std::pair<vh, vh>;
204 using cell = std::array<vh, 3>;
205 using cell_list = std::vector<cell>;
206 static constexpr auto X = Real(0.525731112119133606);
207 static constexpr auto Z = Real(0.850650808352039932);
208 auto g =
grid{
vec{-X, 0, Z},
vec{X, 0, Z},
vec{-X, 0, -Z},
vec{X, 0, -Z},
209 vec{0, Z, X},
vec{0, Z, -X},
vec{0, -Z, X},
vec{0, -Z, -X},
210 vec{Z, X, 0},
vec{-Z, X, 0},
vec{Z, -X, 0},
vec{-Z, -X, 0}};
211 auto triangles = cell_list{
212 {vh{0}, vh{4}, vh{1}}, {vh{0}, vh{9}, vh{4}}, {vh{9}, vh{5}, vh{4}},
213 {vh{4}, vh{5}, vh{8}}, {vh{4}, vh{8}, vh{1}}, {vh{8}, vh{10}, vh{1}},
214 {vh{8}, vh{3}, vh{10}}, {vh{5}, vh{3}, vh{8}}, {vh{5}, vh{2}, vh{3}},
215 {vh{2}, vh{7}, vh{3}}, {vh{7}, vh{10}, vh{3}}, {vh{7}, vh{6}, vh{10}},
216 {vh{7}, vh{11}, vh{6}}, {vh{11}, vh{0}, vh{6}}, {vh{0}, vh{1}, vh{6}},
217 {vh{6}, vh{1}, vh{10}}, {vh{9}, vh{0}, vh{11}}, {vh{9}, vh{11}, vh{2}},
218 {vh{9}, vh{2}, vh{5}}, {vh{7}, vh{2}, vh{11}}};
220 for (std::size_t i = 0; i < num_subdivisions; ++i) {
221 auto subdivided_cells = cell_list{};
222 auto subdivided = std::map<edge, std::size_t>{};
223 for (
auto &[v0, v1, v2] : triangles) {
224 auto edges = std::array{edge{v0, v1}, edge{v0, v2}, edge{v1, v2}};
225 auto nvs = cell{vh{0}, vh{0}, vh{0}};
226 auto i = std::size_t{};
227 for (
auto &edge : edges) {
228 auto &[v0, v1] = edge;
232 if (subdivided.find(edge) ==
end(subdivided)) {
233 subdivided[edge] =
vertices(g).size();
234 nvs[i++] = g.insert_vertex(
normalize((g[v0] + g[v1]) * 0.5));
236 nvs[i++] = vh{subdivided[edge]};
239 subdivided_cells.emplace_back(cell{v0, nvs[1], nvs[0]});
240 subdivided_cells.emplace_back(cell{nvs[0], nvs[2], v1});
241 subdivided_cells.emplace_back(cell{nvs[1], v2, nvs[2]});
242 subdivided_cells.emplace_back(cell{nvs[0], nvs[1], nvs[2]});
244 triangles = subdivided_cells;
246 for (
auto v : g.vertices()) {
249 for (
auto const &c : triangles) {
250 g.insert_triangle(c[0], c[1], c[2]);
266 auto const [axes, lengths] =
main_axes();
267 return axes * diag(lengths);
271template <
typename Real, std::
size_t NumDimensions>
272 requires(NumDimensions == 2 || NumDimensions == 3)
274 std::size_t
const n = 32) {
277template <std::
size_t NumDimensions>
283namespace detail::geometry::hyper_ellipse {
285template <
floating_po
int Real, std::
size_t NumDimensions>
288template <
floating_po
int Real, std::
size_t NumDimensions>
300 : std::integral_constant<bool, std::is_class_v<T> &&decltype(is_derived<T>(
308static_assert(is_derived_from_hyper_ellipse<geometry::HyperEllipse<2>>);
327template <range Ellipso
ids>
329 std::ranges::range_value_t<Ellipsoids>>) &&
330 (std::ranges::range_value_t<Ellipsoids>::num_dimensions() == 2)
331auto write_vtp(Ellipsoids
const &ellipsoids, filesystem::path
const &path) {
332 using namespace std::ranges;
333 using ellipsoid_t = std::ranges::range_value_t<Ellipsoids>;
334 using real_t =
typename ellipsoid_t::real_type;
335 auto file = std::ofstream{path, std::ios::binary};
336 if (!file.is_open()) {
337 throw std::runtime_error{
"Could not write " + path.string()};
339 auto appended_data_offset = std::size_t{};
340 using header_type = std::uint64_t;
341 using connectivity_int = std::int32_t;
342 using offset_int = connectivity_int;
344 <<
" type=\"PolyData\""
345 <<
" version=\"1.0\" "
346 "byte_order=\"LittleEndian\""
347 <<
" header_type=\"" << vtk::xml::to_data_type<header_type>() <<
"\">";
348 file <<
"<PolyData>\n";
349 auto discretized_unit_circle =
351 discretized_unit_circle.set_closed(
true);
352 auto transformed_circle = discretized_unit_circle;
353 auto const num_points = discretized_unit_circle.vertices().size();
354 auto const num_lines = discretized_unit_circle.num_line_segments();
356 auto offsets = std::vector<offset_int>(num_lines, 2);
358 for (std::size_t i = 1; i <
size(offsets); ++i) {
359 offsets[i] += offsets[i - 1];
362 auto connectivity_data = std::vector<connectivity_int>{};
363 connectivity_data.reserve(num_lines * 2);
364 for (connectivity_int i = 0; i < static_cast<connectivity_int>(
365 discretized_unit_circle.num_vertices()) -
368 connectivity_data.push_back(i);
369 connectivity_data.push_back(i + 1);
371 if (discretized_unit_circle.is_closed()) {
372 connectivity_data.push_back(
static_cast<connectivity_int
>(
373 discretized_unit_circle.num_vertices() - 1));
374 connectivity_data.push_back(0);
377 auto const num_bytes_points = header_type(3 * num_points *
sizeof(real_t));
378 auto const num_bytes_connectivity =
379 header_type(num_lines * 2 *
sizeof(connectivity_int));
380 auto const num_bytes_offsets =
381 header_type(offsets.size() *
sizeof(offset_int));
382 for (std::size_t i = 0; i <
size(ellipsoids); ++i) {
384 <<
" NumberOfPoints=\"" << num_points <<
"\""
385 <<
" NumberOfLines=\"" << num_lines <<
"\""
388 auto const points_base =
389 num_bytes_offsets + num_bytes_connectivity +
sizeof(header_type) * 2;
391 file <<
"<Points>\n";
393 <<
" format=\"appended\""
394 <<
" offset=\"" << points_base + appended_data_offset <<
"\""
395 <<
" type=\"" << vtk::xml::to_data_type<real_t>()
396 <<
"\" NumberOfComponents=\"" << 3 <<
"\"/>\n";
397 appended_data_offset += num_bytes_points +
sizeof(header_type);
398 file <<
"</Points>\n";
403 file <<
"<DataArray format=\"appended\" offset=\"0\" type =\""
404 << vtk::xml::to_data_type<connectivity_int>()
405 <<
"\" Name=\"connectivity\"/>\n";
408 file <<
"<DataArray format=\"appended\" offset=\""
409 << num_bytes_connectivity +
sizeof(header_type) <<
"\" type =\""
410 << vtk::xml::to_data_type<offset_int>() <<
"\" Name =\"offsets\"/>\n";
411 file <<
"</Lines>\n";
412 file <<
"</Piece>\n";
414 file <<
"</PolyData>\n";
415 file <<
"<AppendedData encoding=\"raw\">_";
418 file.write(
reinterpret_cast<char const *
>(&num_bytes_connectivity),
419 sizeof(header_type));
420 file.write(
reinterpret_cast<char const *
>(connectivity_data.data()),
421 num_bytes_connectivity);
424 file.write(
reinterpret_cast<char const *
>(&num_bytes_offsets),
425 sizeof(header_type));
426 file.write(
reinterpret_cast<char const *
>(offsets.data()), num_bytes_offsets);
429 for (
auto const &ellipsoid : ellipsoids) {
430 for (
auto v : discretized_unit_circle.vertices()) {
431 transformed_circle[v] =
432 ellipsoid.center() + ellipsoid.S() * discretized_unit_circle[v];
436 file.write(
reinterpret_cast<char const *
>(&num_bytes_points),
437 sizeof(header_type));
438 auto zero = real_t{};
439 for (
auto const v : transformed_circle.vertices()) {
441 reinterpret_cast<char const *
>(transformed_circle.at(v).data()),
443 file.write(
reinterpret_cast<char const *
>(&zero),
sizeof(real_t));
446 file <<
"</AppendedData>";
447 file <<
"</VTKFile>";
450template <range Ellipso
ids>
452 std::ranges::range_value_t<Ellipsoids>>) &&
453 (std::ranges::range_value_t<Ellipsoids>::num_dimensions() == 3)
454auto write_vtp(Ellipsoids
const &ellipsoids, filesystem::path
const &path) {
455 using namespace std::ranges;
456 using ellipsoid_t = std::ranges::range_value_t<Ellipsoids>;
457 using real_t =
typename ellipsoid_t::real_type;
458 auto file = std::ofstream{path, std::ios::binary};
459 if (!file.is_open()) {
460 throw std::runtime_error{
"Could not write " + path.string()};
462 auto offset = std::size_t{};
463 using header_type = std::uint64_t;
464 using connectivity_int = std::int32_t;
465 using offset_int = connectivity_int;
467 <<
" type=\"PolyData\""
468 <<
" version=\"1.0\" "
469 "byte_order=\"LittleEndian\""
470 <<
" header_type=\"" << vtk::xml::to_data_type<header_type>() <<
"\">";
471 file <<
"<PolyData>\n";
472 auto const discretized_unit_sphere =
474 auto transformed_ellipse = discretized_unit_sphere;
475 auto const num_points = discretized_unit_sphere.vertices().size();
476 auto const num_polys = discretized_unit_sphere.triangles().size();
478 auto offsets = std::vector<offset_int>(num_polys, 3);
480 for (std::size_t i = 1; i <
size(offsets); ++i) {
481 offsets[i] += offsets[i - 1];
484 auto index = [](
auto const handle) -> connectivity_int {
487 auto connectivity_data = std::vector<connectivity_int>(num_polys * 3);
488 copy(discretized_unit_sphere.simplices().data_container() |
489 views::transform(
index),
490 begin(connectivity_data));
492 auto const num_bytes_connectivity = num_polys * 3 *
sizeof(connectivity_int);
493 auto const num_bytes_offsets =
sizeof(offset_int) * offsets.size();
494 for (std::size_t i = 0; i <
size(ellipsoids); ++i) {
496 <<
" NumberOfPoints=\"" << num_points <<
"\""
497 <<
" NumberOfPolys=\"" << num_polys <<
"\""
498 <<
" NumberOfVerts=\"0\""
499 <<
" NumberOfLines=\"0\""
500 <<
" NumberOfStrips=\"0\""
506 <<
" format=\"appended\""
507 <<
" offset=\"" << offset <<
"\""
508 <<
" type=\"" << vtk::xml::to_data_type<real_t>()
509 <<
"\" NumberOfComponents=\"" << 3 <<
"\"/>";
510 auto const num_bytes_points = header_type(
sizeof(real_t) * 3 * num_points);
511 offset += num_bytes_points +
sizeof(header_type);
512 file <<
"</Points>\n";
517 file <<
"<DataArray format=\"appended\" offset=\"" << offset <<
"\" type=\""
518 << vtk::xml::to_data_type<connectivity_int>()
519 <<
"\" Name=\"connectivity\"/>\n";
520 offset += num_bytes_connectivity +
sizeof(header_type);
522 file <<
"<DataArray format=\"appended\" offset=\"" << offset <<
"\" type=\""
523 << vtk::xml::to_data_type<offset_int>() <<
"\" Name=\"offsets\"/>\n";
524 offset += num_bytes_offsets +
sizeof(header_type);
525 file <<
"</Polys>\n";
526 file <<
"</Piece>\n";
528 file <<
"</PolyData>\n";
529 file <<
"<AppendedData encoding=\"raw\">_";
531 for (
auto const &ellipsoid : ellipsoids) {
532 for (
auto v : discretized_unit_sphere.vertices()) {
533 transformed_ellipse[v] =
534 ellipsoid.center() + ellipsoid.S() * discretized_unit_sphere[v];
536 auto const num_bytes_points = header_type(
sizeof(real_t) * 3 * num_points);
539 file.write(
reinterpret_cast<char const *
>(&num_bytes_points),
540 sizeof(header_type));
541 for (
auto const v : transformed_ellipse.vertices()) {
543 reinterpret_cast<char const *
>(transformed_ellipse.at(v).data()),
548 file.write(
reinterpret_cast<char const *
>(&num_bytes_connectivity),
549 sizeof(header_type));
550 file.write(
reinterpret_cast<char const *
>(connectivity_data.data()),
551 num_bytes_connectivity);
554 file.write(
reinterpret_cast<char const *
>(&num_bytes_offsets),
555 sizeof(header_type));
556 file.write(
reinterpret_cast<char const *
>(offsets.data()),
559 file <<
"</AppendedData>";
560 file <<
"</VTKFile>";
Definition: grid_edge.h:16
Definition: concepts.h:33
Definition: tensor_concepts.h:88
Definition: tensor_concepts.h:33
auto is_derived(...) -> std::true_type
auto ptr_convertible(he_t< Real, NumDimensions > const volatile *) -> std::true_type
auto discretize(hyper_ellipse< Real, NumDimensions > const &s, std::size_t const n=32)
Definition: hyper_ellipse.h:273
Definition: linspace.h:172
Definition: algorithm.h:6
constexpr auto distance(Iter const &it0, Iter const &it1)
Definition: iterator_facade.h:372
constexpr auto squared_euclidean_length(base_tensor< Tensor, T, N > const &t_in)
Definition: length.h:7
auto begin(Range &&range)
Definition: iterator_facade.h:318
auto end(Range &&range)
Definition: iterator_facade.h:322
auto discretize(polymorphic::field< VReal, NumDimensions, Tensor > const &f, rectilinear_grid< SpatialDimensions... > const &discretized_domain, arithmetic auto const t, execution_policy_tag auto const pol) -> auto
Definition: discretize_field.h:92
auto vertices(pointset< Real, NumDimensions > const &ps)
Definition: vertex_container.h:278
auto eigenvectors_sym(Mat &&A)
Definition: eigenvalues.h:44
auto solve(polynomial< Real, 1 > const &p) -> std::vector< Real >
solve a + b*x
Definition: polynomial.h:187
auto constexpr index(handle< Child, Int > const h)
Definition: handle.h:119
auto write_vtp(Lines const &lines, filesystem::path const &path) -> void
Definition: write.h:38
constexpr auto euclidean_length(base_tensor< Tensor, T, N > const &t_in) -> T
Definition: length.h:12
constexpr auto normalize(base_tensor< Tensor, T, N > const &t_in) -> vec< T, N >
Definition: tensor_operations.h:100
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
auto transposed(dynamic_tensor auto &&t)
Definition: transposed_tensor.h:170
constexpr auto squared_euclidean_distance(base_tensor< Tensor0, T0, N > const &lhs, base_tensor< Tensor1, T1, N > const &rhs)
Definition: distance.h:11
constexpr auto eigenvalues_sym(Mat &&A)
Definition: eigenvalues.h:55
constexpr auto sqrt(arithmetic auto const x)
Definition: math.h:29
static auto constexpr is_derived_from_hyper_ellipse
Definition: hyper_ellipse.h:306
auto Q(V &&v)
Definition: Q_field.h:57
Definition: base_tensor.h:23
Definition: hyper_ellipse.h:301
Definition: vertex_handle.h:10
Definition: hyper_ellipse.h:12
auto euclidean_distance_to_center(pos_type const &x) const
Definition: hyper_ellipse.h:105
auto center() const -> auto const &
Definition: hyper_ellipse.h:91
auto squared_local_euclidean_distance_to_center(pos_type const &x) const
Definition: hyper_ellipse.h:109
vec_type m_center
Definition: hyper_ellipse.h:23
auto discretize(std::size_t const num_subdivisions=2) const
Definition: hyper_ellipse.h:198
constexpr hyper_ellipse(fixed_size_vec< NumDimensions > auto const ¢er, fixed_size_quadratic_mat< NumDimensions > auto const &S)
Sets up a sphere with specified radius and origin point.
Definition: hyper_ellipse.h:53
constexpr hyper_ellipse(arithmetic auto const ... radii)
Sets up a sphere with specified radii.
Definition: hyper_ellipse.h:67
auto center(std::size_t const i) -> auto &
Definition: hyper_ellipse.h:95
constexpr hyper_ellipse(fixed_size_quadratic_mat< NumDimensions > auto const &H)
Fits an ellipse through specified points.
Definition: hyper_ellipse.h:83
mat_type m_S
Definition: hyper_ellipse.h:24
hyper_ellipse< Real, NumDimensions > this_type
Definition: hyper_ellipse.h:14
constexpr auto is_inside(pos_type const &x) const
Definition: hyper_ellipse.h:174
constexpr hyper_ellipse()
defaults to unit hypersphere
Definition: hyper_ellipse.h:29
constexpr hyper_ellipse(vec_type const ¢er, Real const radius)
Sets up a sphere with specified radius and origin point.
Definition: hyper_ellipse.h:49
constexpr auto fit(fixed_size_quadratic_mat< NumDimensions > auto const &H)
Definition: hyper_ellipse.h:157
auto S() -> auto &
Definition: hyper_ellipse.h:89
constexpr hyper_ellipse(hyper_ellipse &&) noexcept=default
vec< Real, NumDimensions > vec_type
Definition: hyper_ellipse.h:15
constexpr auto fit(fixed_size_vec< NumDimensions > auto const &...points)
Fits an ellipse through specified points.
Definition: hyper_ellipse.h:149
constexpr hyper_ellipse(Real const radius, vec_type const ¢er)
Sets up a sphere with specified radius and origin point.
Definition: hyper_ellipse.h:45
auto squared_euclidean_distance_to_center(pos_type const &x) const
Definition: hyper_ellipse.h:101
Real real_type
Definition: hyper_ellipse.h:18
constexpr hyper_ellipse(vec_type const ¢er, arithmetic auto const ... radii)
Sets up a sphere with specified radii.
Definition: hyper_ellipse.h:58
auto local_coordinate(pos_type const &x) const
Definition: hyper_ellipse.h:97
auto radii() const
Returns a the radii of the hyper ellipse as a vector.
Definition: hyper_ellipse.h:262
auto nearest_point_boundary(pos_type const &x) const
Definition: hyper_ellipse.h:131
auto discretize(std::size_t const num_vertices=32) const
Definition: hyper_ellipse.h:178
auto local_distance_to_center(pos_type const &x) const
Definition: hyper_ellipse.h:113
static auto constexpr num_dimensions()
Definition: hyper_ellipse.h:19
auto center(std::size_t const i) const
Definition: hyper_ellipse.h:94
constexpr hyper_ellipse(fixed_size_vec< NumDimensions > auto const &...points)
Fits an ellipse through specified points.
Definition: hyper_ellipse.h:76
constexpr auto distance_to_boundary(pos_type const &x) const
Computes euclidean distance to nearest boundary point.
Definition: hyper_ellipse.h:118
constexpr hyper_ellipse(hyper_ellipse const &)=default
auto center() -> auto &
Definition: hyper_ellipse.h:92
constexpr auto nearest_point_on_boundary(base_tensor< V, VReal, NumDimensions > const &x) const
Definition: hyper_ellipse.h:166
auto main_axes() const
Definition: hyper_ellipse.h:259
auto local_nearest_point_boundary(pos_type const &x) const
Definition: hyper_ellipse.h:126
auto S() const -> auto const &
Definition: hyper_ellipse.h:88
auto base_coordinate_system() const
Returns a the radii of the hyper ellipse as a vector.
Definition: hyper_ellipse.h:265
constexpr auto fit(std::index_sequence< Is... >, fixed_size_vec< NumDimensions > auto const &...points)
Fits an ellipse through specified points.
Definition: hyper_ellipse.h:139
auto index() const
Definition: handle.h:64
Definition: linspace.h:26
constexpr auto pop_back()
Definition: linspace.h:107
static auto constexpr eye()
Definition: mat.h:46
Definition: unstructured_triangular_grid.h:10
static auto constexpr zeros()
Definition: vec.h:26