15#ifndef CDT_PLUSPLUS_ERGODIC_MOVES_3_HPP
16#define CDT_PLUSPLUS_ERGODIC_MOVES_3_HPP
24namespace ergodic_moves
27 using Expected = std::expected<Manifold, std::string>;
28 using Cell_handle = Cell_handle_t<3>;
29 using Cell_container = std::vector<Cell_handle>;
30 using Edge_handle = Edge_handle_t<3>;
31 using Edge_container = std::vector<Edge_handle>;
32 using Vertex_handle = Vertex_handle_t<3>;
33 using Vertex_container = std::vector<Vertex_handle>;
34 using Delaunay = Delaunay_t<3>;
53 Cell_handle
const& to_be_moved) ->
bool
55 if (to_be_moved->info() != 22) {
return false; }
58 for (
auto i = 0; i < 4; ++i)
60 if (t_manifold.triangulation().flip(to_be_moved, i))
63 spdlog::trace(
"Facet {} was flippable.\n", i);
69 spdlog::trace(
"Facet {} was not flippable.\n", i);
90 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
93 auto two_two = t_manifold.get_triangulation().get_two_two();
95 std::ranges::shuffle(two_two, utilities::make_random_generator());
97 if (std::ranges::any_of(
98 two_two, [&](
auto& cell) {
return try_23_move(t_manifold, cell); }))
103 std::string
const msg =
"No (2,3) move possible.\n";
105 return std::unexpected(msg);
115 Edge_handle
const& to_be_moved) ->
bool
117 return t_manifold.triangulation().flip(
118 to_be_moved.first, to_be_moved.second, to_be_moved.third);
132 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
134 auto timelike_edges = t_manifold.get_timelike_edges();
136 std::ranges::shuffle(timelike_edges, utilities::make_random_generator());
138 if (std::ranges::any_of(timelike_edges, [&](
auto& edge) {
145 std::string
const msg =
"No (3,2) move possible.\n";
147 return std::unexpected(msg);
156 -> std::optional<int>
158 if (t_cell->info() != 13) {
return std::nullopt; }
159 for (
auto i = 0; i < 4; ++i)
162 spdlog::trace(
"Neighbor {} is of type {}\n", i,
163 t_cell->neighbor(i)->info());
165 if (foliated_triangulations::expected_cell_type<3>(t_cell->neighbor(i)) ==
166 Cell_type::THREE_ONE)
168 return std::make_optional(i);
191 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
193 static auto constexpr INCIDENT_CELLS_FOR_6_2_MOVE = 6;
194 auto one_three = t_manifold.get_triangulation().get_one_three();
196 std::ranges::shuffle(one_three, utilities::make_random_generator());
197 for (
auto const& bottom : one_three)
200 neighboring_31_index)
203 spdlog::trace(
"neighboring_31_index is {}.\n", *neighboring_31_index);
205 Cell_handle
const top = bottom->neighbor(neighboring_31_index.value());
207 auto common_face_index = std::numeric_limits<int>::max();
208 if (!bottom->has_neighbor(top, common_face_index))
210 std::string
const msg =
"Bottom cell does not have a neighbor.\n";
214 return std::unexpected(msg);
223 auto const i_1 = (common_face_index + 1) % 4;
224 auto const i_2 = (common_face_index + 2) % 4;
225 auto const i_3 = (common_face_index + 3) % 4;
228 auto const v_1 = bottom->vertex(i_1);
229 auto const v_2 = bottom->vertex(i_2);
230 auto const v_3 = bottom->vertex(i_3);
233 if (v_1->info() != v_2->info() || v_2->info() != v_3->info())
235 std::string
const msg =
"Vertices have different timeslices.\n";
239 return std::unexpected(msg);
244 Vertex_handle
const v_center =
245 t_manifold.triangulation().delaunay().tds().insert_in_facet(
246 bottom, *neighboring_31_index);
249 Cell_container incident_cells;
250 t_manifold.triangulation().delaunay().tds().incident_cells(
251 v_center, std::back_inserter(incident_cells));
253 if (incident_cells.size() != INCIDENT_CELLS_FOR_6_2_MOVE)
255 std::string
const msg =
256 "Center vertex is not bounded by 6 simplices.\n";
260 return std::unexpected(msg);
264 if (
auto check_cells =
265 std::ranges::all_of(incident_cells,
266 [&t_manifold](
auto const& cell) {
267 return t_manifold.get_triangulation()
274 std::string
const msg =
"A cell is invalid.\n";
278 return std::unexpected(msg);
283 CGAL::centroid(v_1->point(), v_2->point(), v_3->point());
285 spdlog::trace(
"Center point is: ({}).\n",
286 utilities::point_to_str(center_point));
288 v_center->set_point(center_point);
291 auto timevalue = v_1->info();
292 v_center->info() = timevalue;
295 if (t_manifold.is_vertex(v_center))
297 spdlog::trace(
"It's a vertex in the TDS.\n");
299 else { spdlog::trace(
"It's not a vertex in the TDS.\n"); }
300 spdlog::trace(
"Spacelike face timevalue is {}.\n", timevalue);
301 spdlog::trace(
"Inserted vertex ({}) with timevalue {}.\n",
302 utilities::point_to_str(v_center->point()),
308 if (!t_manifold.get_delaunay().tds().is_valid(v_center,
true, 1))
310 std::string
const msg =
"v_center is invalid.\n";
314 return std::unexpected(msg);
321 spdlog::debug(
"Cell not insertable.\n");
325 std::string
const msg =
"No (2,6) move possible.\n";
327 return std::unexpected(msg);
339 Vertex_handle
const& candidate)
342 if (manifold.dimensionality() != 3)
345 spdlog::trace(
"Manifold is not 3-dimensional.\n");
350 if (!manifold.is_vertex(candidate))
353 spdlog::trace(
"Candidate is not a vertex.\n");
359 if (
auto incident_edges = manifold.degree(candidate);
363 spdlog::trace(
"Vertex has {} incident edges.\n", incident_edges);
369 auto const incident_cells = manifold.incident_cells(candidate);
372 if (incident_cells.size() != 6)
375 spdlog::trace(
"Vertex has {} incident cells.\n", incident_cells.size());
381 for (
auto const& cell : incident_cells)
383 if (manifold.get_triangulation().is_infinite(cell))
386 spdlog::trace(
"Cell is infinite.\n");
393 while (foliated_triangulations::fix_vertices<3>(
394 manifold.get_delaunay(), manifold.initial_radius(),
395 manifold.foliation_spacing()))
397 spdlog::warn(
"Fixing vertices found by is_62_movable().\n");
413 auto const incident_31 = foliated_triangulations::filter_cells<3>(
414 incident_cells, Cell_type::THREE_ONE);
415 auto const incident_22 = foliated_triangulations::filter_cells<3>(
416 incident_cells, Cell_type::TWO_TWO);
417 auto const incident_13 = foliated_triangulations::filter_cells<3>(
418 incident_cells, Cell_type::ONE_THREE);
421 if (incident_13.size() + incident_22.size() + incident_31.size() !=
424 spdlog::warn(
"Some incident cells on this vertex need to be fixed.\n");
429 "Vertex has {} incident cells with {} incident (3,1) simplices and {} "
430 "incident (2,2) simplices and {} incident (1,3) simplices.\n",
431 incident_cells.size(), incident_31.size(), incident_22.size(),
433 foliated_triangulations::debug_print_cells<3>(std::span{incident_cells});
435 return incident_31.size() == 3 && incident_22.empty() &&
436 incident_13.size() == 3;
461 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
463 auto vertices = t_manifold.get_vertices();
465 std::ranges::shuffle(vertices, utilities::make_random_generator());
467 if (
auto const movable_vertex_iterator =
468 std::ranges::find_if(vertices,
469 [&](
auto const& vertex) {
472 movable_vertex_iterator != vertices.end())
474 t_manifold.triangulation().delaunay().remove(*movable_vertex_iterator);
478 std::string
const msg =
"No (6,2) move possible.\n";
480 return std::unexpected(msg);
490 Delaunay_t<3>
const& triangulation, Edge_handle
const& edge)
491 -> std::optional<Cell_container>
493 if (!triangulation.tds().is_edge(edge.first, edge.second, edge.third))
499 auto circulator = triangulation.incident_cells(edge, edge.first);
500 Cell_container incident_cells;
505 if (triangulation.is_infinite(circulator)) {
continue; }
506 incident_cells.emplace_back(circulator);
508 while (++circulator != edge.first);
510 spdlog::trace(
"Found {} incident cells on edge.\n", incident_cells.size());
512 return incident_cells;
524 Delaunay
const& triangulation, Edge_handle
const& t_edge_candidate)
525 -> std::optional<Cell_container>
527 if (
auto incident_cells =
529 incident_cells.has_value() && incident_cells->size() == 4)
531 return incident_cells.value();
541 Edge_handle
const edge)
542 -> std::optional<Cell_container>
545 if (!triangulation.tds().is_edge(edge.first, edge.second, edge.third))
550 Cell_container incident_cells;
551 auto circulator = triangulation.incident_cells(edge, edge.first);
554 if (triangulation.is_infinite(circulator)) {
continue; }
555 incident_cells.emplace_back(circulator);
557 while (++circulator != edge.first);
559 return incident_cells;
571 Edge_handle edge, Vertex_handle top,
572 Vertex_handle bottom)
573 -> std::optional<Delaunay>
579 if (!incident_cells || incident_cells->size() != 4) {
return std::nullopt; }
582 if (std::ranges::any_of(*incident_cells,
583 [](
auto const& cell) {
return !cell->is_valid(); }))
589 auto const& pivot_from_1 = edge.first->vertex(edge.second);
590 auto const& pivot_from_2 = edge.first->vertex(edge.third);
593 auto vertices = foliated_triangulations::get_vertices_from_cells<3>(
594 incident_cells.value());
597 Vertex_container new_pivot_vertices;
598 std::ranges::copy_if(vertices, std::back_inserter(new_pivot_vertices),
599 [&](
auto const& vertex) {
600 return vertex != pivot_from_1 &&
601 vertex != pivot_from_2 && vertex != top &&
606 if (new_pivot_vertices.size() != 2) {
return std::nullopt; }
609 auto const& pivot_to_1 = new_pivot_vertices[0];
610 auto const& pivot_to_2 = new_pivot_vertices[1];
613 if (triangulation.is_infinite(pivot_from_1) ||
614 triangulation.is_infinite(pivot_from_2) ||
615 triangulation.is_infinite(pivot_to_1) ||
616 triangulation.is_infinite(pivot_to_2) ||
617 triangulation.is_infinite(top) || triangulation.is_infinite(bottom))
624 "Pivot from: ({}, {}), Pivot to: ({}, {}), Top: {}, Bottom: {}",
625 pivot_from_1->point(), pivot_from_2->point(), pivot_to_1->point(),
626 pivot_to_2->point(), top->point(), bottom->point());
630 Cell_handle before_1 =
632 Cell_handle before_2 =
634 Cell_handle before_3 =
636 Cell_handle before_4 =
639 for (
auto const& cell : incident_cells.value())
641 if (cell->has_vertex(top))
643 if (cell->has_vertex(pivot_to_1)) { before_1 = cell; }
644 else { before_2 = cell; }
648 if (cell->has_vertex(pivot_to_1)) { before_3 = cell; }
649 else { before_4 = cell; }
654 if (before_1 ==
nullptr || before_2 ==
nullptr || before_3 ==
nullptr ||
658 spdlog::debug(
"Not all cells were properly identified.");
664 if (triangulation.is_infinite(before_1) ||
665 triangulation.is_infinite(before_2) ||
666 triangulation.is_infinite(before_3) ||
667 triangulation.is_infinite(before_4) || !before_1->is_valid() ||
668 !before_2->is_valid() || !before_3->is_valid() || !before_4->is_valid())
671 spdlog::debug(
"Some cells are invalid or infinite.");
677 spdlog::debug(
"Cells in the triangulation before deleting old cells: {}",
678 triangulation.number_of_cells());
681 spdlog::debug(
"Before_1: vertices {}, {}, {}, {}",
682 before_1->vertex(0)->point(), before_1->vertex(1)->point(),
683 before_1->vertex(2)->point(), before_1->vertex(3)->point());
684 spdlog::debug(
"Before_2: vertices {}, {}, {}, {}",
685 before_2->vertex(0)->point(), before_2->vertex(1)->point(),
686 before_2->vertex(2)->point(), before_2->vertex(3)->point());
687 spdlog::debug(
"Before_3: vertices {}, {}, {}, {}",
688 before_3->vertex(0)->point(), before_3->vertex(1)->point(),
689 before_3->vertex(2)->point(), before_3->vertex(3)->point());
690 spdlog::debug(
"Before_4: vertices {}, {}, {}, {}",
691 before_4->vertex(0)->point(), before_4->vertex(1)->point(),
692 before_4->vertex(2)->point(), before_4->vertex(3)->point());
696 Cell_handle n_1 = before_1->neighbor(before_1->index(pivot_from_2));
697 Cell_handle n_2 = before_1->neighbor(before_1->index(pivot_from_1));
698 Cell_handle n_3 = before_2->neighbor(before_2->index(pivot_from_1));
699 Cell_handle n_4 = before_2->neighbor(before_2->index(pivot_from_2));
700 Cell_handle n_5 = before_3->neighbor(before_3->index(pivot_from_2));
701 Cell_handle n_6 = before_3->neighbor(before_3->index(pivot_from_1));
702 Cell_handle n_7 = before_4->neighbor(before_4->index(pivot_from_1));
703 Cell_handle n_8 = before_4->neighbor(before_4->index(pivot_from_2));
706 int n1_idx = n_1->index(before_1);
707 int n2_idx = n_2->index(before_1);
708 int n3_idx = n_3->index(before_2);
709 int n4_idx = n_4->index(before_2);
710 int n5_idx = n_5->index(before_3);
711 int n6_idx = n_6->index(before_3);
712 int n7_idx = n_7->index(before_4);
713 int n8_idx = n_8->index(before_4);
716 if (n_1 ==
nullptr || n_2 ==
nullptr || n_3 ==
nullptr || n_4 ==
nullptr ||
717 n_5 ==
nullptr || n_6 ==
nullptr || n_7 ==
nullptr || n_8 ==
nullptr ||
718 n_1 == before_1 || n_1 == before_2 || n_1 == before_3 ||
719 n_1 == before_4 || n_2 == before_1 || n_2 == before_2 ||
720 n_2 == before_3 || n_2 == before_4 || n_3 == before_1 ||
721 n_3 == before_2 || n_3 == before_3 || n_3 == before_4 ||
722 n_4 == before_1 || n_4 == before_2 || n_4 == before_3 ||
723 n_4 == before_4 || n_5 == before_1 || n_5 == before_2 ||
724 n_5 == before_3 || n_5 == before_4 || n_6 == before_1 ||
725 n_6 == before_2 || n_6 == before_3 || n_6 == before_4 ||
726 n_7 == before_1 || n_7 == before_2 || n_7 == before_3 ||
727 n_7 == before_4 || n_8 == before_1 || n_8 == before_2 ||
728 n_8 == before_3 || n_8 == before_4)
731 spdlog::debug(
"Issue with neighbors");
739 triangulation.tds().set_adjacency(before_1, before_1->index(pivot_from_2),
741 triangulation.tds().set_adjacency(before_1, before_1->index(pivot_from_1),
743 triangulation.tds().set_adjacency(before_2, before_2->index(pivot_from_1),
745 triangulation.tds().set_adjacency(before_2, before_2->index(pivot_from_2),
747 triangulation.tds().set_adjacency(before_3, before_3->index(pivot_from_2),
749 triangulation.tds().set_adjacency(before_3, before_3->index(pivot_from_1),
751 triangulation.tds().set_adjacency(before_4, before_4->index(pivot_from_1),
753 triangulation.tds().set_adjacency(before_4, before_4->index(pivot_from_2),
757 triangulation.tds().delete_cell(before_1);
758 triangulation.tds().delete_cell(before_2);
759 triangulation.tds().delete_cell(before_3);
760 triangulation.tds().delete_cell(before_4);
763 spdlog::debug(
"Cells in the triangulation after deleting old cells: {}",
764 triangulation.number_of_cells());
769 Cell_handle after_1 = triangulation.tds().create_cell(
770 pivot_to_1, pivot_to_2, pivot_from_1, top);
771 Cell_handle after_2 = triangulation.tds().create_cell(
772 pivot_to_1, pivot_to_2, pivot_from_2, top);
773 Cell_handle after_3 = triangulation.tds().create_cell(
774 pivot_to_1, pivot_to_2, pivot_from_1, bottom);
775 Cell_handle after_4 = triangulation.tds().create_cell(
776 pivot_to_1, pivot_to_2, pivot_from_2, bottom);
779 if (after_1 ==
nullptr || after_2 ==
nullptr || after_3 ==
nullptr ||
780 after_4 ==
nullptr || !after_1->is_valid() || !after_2->is_valid() ||
781 !after_3->is_valid() || !after_4->is_valid())
784 spdlog::debug(
"Failed to create new cells properly");
791 after_1->info() = before_1->info();
792 after_2->info() = before_2->info();
793 after_3->info() = before_3->info();
794 after_4->info() = before_4->info();
797 spdlog::debug(
"After_1: vertices {}, {}, {}, {}",
798 after_1->vertex(0)->point(), after_1->vertex(1)->point(),
799 after_1->vertex(2)->point(), after_1->vertex(3)->point());
800 spdlog::debug(
"After_2: vertices {}, {}, {}, {}",
801 after_2->vertex(0)->point(), after_2->vertex(1)->point(),
802 after_2->vertex(2)->point(), after_2->vertex(3)->point());
803 spdlog::debug(
"After_3: vertices {}, {}, {}, {}",
804 after_3->vertex(0)->point(), after_3->vertex(1)->point(),
805 after_3->vertex(2)->point(), after_3->vertex(3)->point());
806 spdlog::debug(
"After_4: vertices {}, {}, {}, {}",
807 after_4->vertex(0)->point(), after_4->vertex(1)->point(),
808 after_4->vertex(2)->point(), after_4->vertex(3)->point());
814 int after_1_after_2_idx = after_1->index(pivot_from_1);
815 int after_2_after_1_idx = after_2->index(pivot_from_2);
817 int after_1_after_3_idx = after_1->index(top);
818 int after_3_after_1_idx = after_3->index(bottom);
820 int after_2_after_4_idx = after_2->index(top);
821 int after_4_after_2_idx = after_4->index(bottom);
823 int after_3_after_4_idx = after_3->index(pivot_from_1);
824 int after_4_after_3_idx = after_4->index(pivot_from_2);
827 triangulation.tds().set_adjacency(after_1, after_1_after_2_idx, after_2,
828 after_2_after_1_idx);
829 triangulation.tds().set_adjacency(after_1, after_1_after_3_idx, after_3,
830 after_3_after_1_idx);
831 triangulation.tds().set_adjacency(after_2, after_2_after_4_idx, after_4,
832 after_4_after_2_idx);
833 triangulation.tds().set_adjacency(after_3, after_3_after_4_idx, after_4,
834 after_4_after_3_idx);
837 if (!after_1->has_neighbor(after_2) || !after_2->has_neighbor(after_1) ||
838 !after_1->has_neighbor(after_3) || !after_3->has_neighbor(after_1) ||
839 !after_2->has_neighbor(after_4) || !after_4->has_neighbor(after_2) ||
840 !after_3->has_neighbor(after_4) || !after_4->has_neighbor(after_3))
843 spdlog::debug(
"Internal neighbor relationships are not set up correctly");
850 int after_1_ext_1_idx = after_1->index(pivot_to_2);
851 int after_1_ext_2_idx = after_1->index(pivot_to_1);
853 int after_2_ext_1_idx = after_2->index(pivot_to_2);
854 int after_2_ext_2_idx = after_2->index(pivot_to_1);
856 int after_3_ext_1_idx = after_3->index(pivot_to_2);
857 int after_3_ext_2_idx = after_3->index(pivot_to_1);
859 int after_4_ext_1_idx = after_4->index(pivot_to_2);
860 int after_4_ext_2_idx = after_4->index(pivot_to_1);
863 triangulation.tds().set_adjacency(after_1, after_1_ext_1_idx, n_1, n1_idx);
864 triangulation.tds().set_adjacency(after_1, after_1_ext_2_idx, n_2, n2_idx);
865 triangulation.tds().set_adjacency(after_2, after_2_ext_1_idx, n_3, n3_idx);
866 triangulation.tds().set_adjacency(after_2, after_2_ext_2_idx, n_4, n4_idx);
867 triangulation.tds().set_adjacency(after_3, after_3_ext_1_idx, n_5, n5_idx);
868 triangulation.tds().set_adjacency(after_3, after_3_ext_2_idx, n_6, n6_idx);
869 triangulation.tds().set_adjacency(after_4, after_4_ext_1_idx, n_7, n7_idx);
870 triangulation.tds().set_adjacency(after_4, after_4_ext_2_idx, n_8, n8_idx);
873 bool external_neighbors_ok = after_1->neighbor(after_1_ext_1_idx) == n_1 &&
874 n_1->neighbor(n1_idx) == after_1 &&
875 after_1->neighbor(after_1_ext_2_idx) == n_2 &&
876 n_2->neighbor(n2_idx) == after_1 &&
877 after_2->neighbor(after_2_ext_1_idx) == n_3 &&
878 n_3->neighbor(n3_idx) == after_2 &&
879 after_2->neighbor(after_2_ext_2_idx) == n_4 &&
880 n_4->neighbor(n4_idx) == after_2 &&
881 after_3->neighbor(after_3_ext_1_idx) == n_5 &&
882 n_5->neighbor(n5_idx) == after_3 &&
883 after_3->neighbor(after_3_ext_2_idx) == n_6 &&
884 n_6->neighbor(n6_idx) == after_3 &&
885 after_4->neighbor(after_4_ext_1_idx) == n_7 &&
886 n_7->neighbor(n7_idx) == after_4 &&
887 after_4->neighbor(after_4_ext_2_idx) == n_8 &&
888 n_8->neighbor(n8_idx) == after_4;
890 if (!external_neighbors_ok)
893 spdlog::debug(
"External neighbor relationships are not set up correctly");
899 spdlog::debug(
"Cells in the triangulation after adding new cells: {}",
900 triangulation.number_of_cells());
903 spdlog::debug(
"after_1 neighbors after_2: {}",
904 after_1->has_neighbor(after_2));
905 spdlog::debug(
"after_2 neighbors after_1: {}",
906 after_2->has_neighbor(after_1));
907 spdlog::debug(
"after_1 neighbors after_3: {}",
908 after_1->has_neighbor(after_3));
909 spdlog::debug(
"after_3 neighbors after_1: {}",
910 after_3->has_neighbor(after_1));
911 spdlog::debug(
"after_2 neighbors after_4: {}",
912 after_2->has_neighbor(after_4));
913 spdlog::debug(
"after_4 neighbors after_2: {}",
914 after_4->has_neighbor(after_2));
915 spdlog::debug(
"after_3 neighbors after_4: {}",
916 after_3->has_neighbor(after_4));
917 spdlog::debug(
"after_4 neighbors after_3: {}",
918 after_4->has_neighbor(after_3));
922 triangulation.tds().reorient();
925 if (!triangulation.tds().is_valid(
true, 4))
928 spdlog::debug(
"Final triangulation is not valid after reorientation");
933 return std::make_optional(triangulation);
938 Edge_container
const& edges)
939 -> std::optional<Edge_handle>
941 for (
auto const& edge : edges)
943 auto circulator = triangulation.incident_cells(edge, edge.first);
944 Cell_container incident_cells;
947 if (triangulation.is_infinite(circulator)) {
continue; }
948 incident_cells.emplace_back(circulator);
950 while (++circulator != edge.first);
951 fmt::print(
"Edge has {} incident finite cells\n", incident_cells.size());
952 if (incident_cells.size() == 4) {
return edge; }
962 std::unordered_set<Vertex_handle> vertices;
964 for (
int i = 0; i < 4; ++i) { vertices.emplace(cell->vertex(i)); }
967 Vertex_container result(vertices.begin(), vertices.end());
994 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
996 auto spacelike_edges = t_manifold.get_spacelike_edges();
998 std::ranges::shuffle(spacelike_edges, utilities::make_random_generator());
999 for (
auto const& edge : spacelike_edges)
1003 t_manifold.get_triangulation().get_delaunay(), edge);
1007 for (
auto const& cell : *incident_cells)
1009 spdlog::trace(
"Incident cell is of type {}.\n", cell->info());
1014 auto const& v1 = edge.first->vertex(edge.second);
1015 auto const& v2 = edge.first->vertex(edge.third);
1018 Vertex_handle top =
nullptr;
1019 Vertex_handle bottom =
nullptr;
1022 for (
auto const& cell : *incident_cells)
1024 for (
int i = 0; i < 4; ++i)
1026 auto vertex = cell->vertex(i);
1027 if (vertex != v1 && vertex != v2)
1030 if (top ==
nullptr || vertex->info() > top->info())
1034 if (bottom ==
nullptr || vertex->info() < bottom->info())
1043 if (
auto flipped_triangulation =
1046 flipped_triangulation.has_value())
1050 auto new_triangulation =
1052 flipped_triangulation.value(), t_manifold.initial_radius(),
1053 t_manifold.foliation_spacing());
1056 auto new_manifold =
Manifold(new_triangulation);
1058 return new_manifold;
1064 spdlog::debug(
"Bistellar flip failed.");
1070 std::string
const msg =
"No (4,4) move possible.\n";
1072 return std::unexpected(msg);
1087 case move_tracker::move_type::FOUR_FOUR:
1088 return t_after.is_valid() && t_after.N3() == t_before.N3() &&
1089 t_after.N3_31() == t_before.N3_31() &&
1090 t_after.N3_22() == t_before.N3_22() &&
1091 t_after.N3_13() == t_before.N3_13() &&
1092 t_after.N2() == t_before.N2() && t_after.N1() == t_before.N1() &&
1093 t_after.N1_TL() == t_before.N1_TL() &&
1094 t_after.N1_SL() == t_before.N1_SL() &&
1095 t_after.N0() == t_before.N0() &&
1096 t_after.max_time() == t_before.max_time() &&
1097 t_after.min_time() == t_before.min_time();
1098 case move_tracker::move_type::TWO_THREE:
1099 return t_after.is_valid() && t_after.N3() == t_before.N3() + 1 &&
1100 t_after.N3_31() == t_before.N3_31() &&
1101 t_after.N3_22() == t_before.N3_22() + 1 &&
1102 t_after.N3_13() == t_before.N3_13() &&
1103 t_after.N2() == t_before.N2() + 2 &&
1104 t_after.N1() == t_before.N1() + 1 &&
1105 t_after.N1_TL() == t_before.N1_TL() + 1 &&
1106 t_after.N1_SL() == t_before.N1_SL() &&
1107 t_after.N0() == t_before.N0() &&
1108 t_after.max_time() == t_before.max_time() &&
1109 t_after.min_time() == t_before.min_time();
1110 case move_tracker::move_type::THREE_TWO:
1111 return t_after.is_valid() && t_after.N3() == t_before.N3() - 1 &&
1112 t_after.N3_31() == t_before.N3_31() &&
1113 t_after.N3_22() == t_before.N3_22() - 1 &&
1114 t_after.N3_13() == t_before.N3_13() &&
1115 t_after.N2() == t_before.N2() - 2 &&
1116 t_after.N1() == t_before.N1() - 1 &&
1117 t_after.N1_TL() == t_before.N1_TL() - 1 &&
1118 t_after.N1_SL() == t_before.N1_SL() &&
1119 t_after.N0() == t_before.N0() &&
1120 t_after.max_time() == t_before.max_time() &&
1121 t_after.min_time() == t_before.min_time();
1122 case move_tracker::move_type::TWO_SIX:
1123 return t_after.is_valid() && t_after.N3() == t_before.N3() + 4 &&
1124 t_after.N3_31() == t_before.N3_31() + 2 &&
1125 t_after.N3_22() == t_before.N3_22() &&
1126 t_after.N3_13() == t_before.N3_13() + 2 &&
1127 t_after.N2() == t_before.N2() + 8 &&
1128 t_after.N1() == t_before.N1() + 5 &&
1129 t_after.N1_TL() == t_before.N1_TL() + 2 &&
1130 t_after.N1_SL() == t_before.N1_SL() + 3 &&
1131 t_after.N0() == t_before.N0() + 1 &&
1132 t_after.max_time() == t_before.max_time() &&
1133 t_after.min_time() == t_before.min_time();
1134 case move_tracker::move_type::SIX_TWO:
1135 return t_after.is_valid() && t_after.N3() == t_before.N3() - 4 &&
1136 t_after.N3_31() == t_before.N3_31() - 2 &&
1137 t_after.N3_22() == t_before.N3_22() &&
1138 t_after.N3_13() == t_before.N3_13() - 2 &&
1139 t_after.N2() == t_before.N2() - 8 &&
1140 t_after.N1() == t_before.N1() - 5 &&
1141 t_after.N1_TL() == t_before.N1_TL() - 2 &&
1142 t_after.N1_SL() == t_before.N1_SL() - 3 &&
1143 t_after.N0() == t_before.N0() - 1 &&
1144 t_after.max_time() == t_before.max_time() &&
1145 t_after.min_time() == t_before.min_time();
1146 default:
return false;
auto bistellar_flip(Delaunay triangulation, Edge_handle edge, Vertex_handle top, Vertex_handle bottom) -> std::optional< Delaunay >
Perform a bistellar flip on triangulation via the given edge.
auto find_adjacent_31_cell(Cell_handle const &t_cell) -> std::optional< int >
Find a (2,6) move location.
auto do_23_move(Manifold &t_manifold) -> Expected
Perform a (2,3) move.
auto try_23_move(Manifold &t_manifold, Cell_handle const &to_be_moved) -> bool
Perform a TriangulationDataStructure_3::flip on a facet.
auto do_32_move(Manifold &t_manifold) -> Expected
Perform a (3,2) move.
auto do_44_move(Manifold const &t_manifold) -> Expected
Perform a (4,4) move.
auto is_62_movable(Manifold const &manifold, Vertex_handle const &candidate) -> bool
Find a (6,2) move location.
auto null_move(Manifold const &t_manifold) noexcept -> Expected
Perform a null move.
auto get_incident_cells(Delaunay const &triangulation, Edge_handle const edge) -> std::optional< Cell_container >
Return a container of cells incident to an edge.
auto do_62_move(Manifold &t_manifold) -> Expected
Perform a (6,2) move.
auto check_move(Manifold const &t_before, Manifold const &t_after, move_tracker::move_type const &t_move) -> bool
Check move correctness.
auto do_26_move(Manifold &t_manifold) -> Expected
Perform a (2,6) move.
auto get_vertices(Cell_container const &cells)
Return a container of all vertices in a container of cells.
auto incident_cells_from_edge(Delaunay_t< 3 > const &triangulation, Edge_handle const &edge) -> std::optional< Cell_container >
Find all cells incident to the edge.
auto try_32_move(Manifold &t_manifold, Edge_handle const &to_be_moved) -> bool
Perform a TriangulationDataStructure_3::flip on an edge.
auto find_bistellar_flip_location(Delaunay const &triangulation, Edge_handle const &t_edge_candidate) -> std::optional< Cell_container >
Find a bistellar flip location.
auto find_pivot_edge(Delaunay const &triangulation, Edge_container const &edges) -> std::optional< Edge_handle >
Data structures for manifolds.
move_type
The types of 3D ergodic moves.