1#ifndef TATOOINE_GEOMETRY_DETAIL_LINE_MERGE_H
2#define TATOOINE_GEOMETRY_DETAIL_LINE_MERGE_H
19template <
typename Real, std::
size_t N>
26 static_cast<std::uint8_t
>(connection) |
31 static_cast<std::uint8_t
>(connection) |
36 static_cast<std::uint8_t
>(connection) |
41 static_cast<std::uint8_t
>(connection) |
48template <
typename Real, std::
size_t N>
70template <
typename Real, std::
size_t N>
74 using std::ranges::copy;
75 using std::ranges::subrange;
76 using std::views::reverse;
78 auto &data0 = line0.vertices().data_container();
79 auto data0_rev = data0 | reverse;
83 auto line0_without_common_vertex =
85 copy(line0_without_common_vertex, std::front_inserter(line1));
90 auto line0_without_common_vertex =
92 copy(line0_without_common_vertex, std::front_inserter(line1));
97 auto line0_without_common_vertex =
99 copy(line0_without_common_vertex, std::back_inserter(line1));
104 auto line0_without_common_vertex =
106 copy(line0_without_common_vertex, std::back_inserter(line1));
116template <
floating_po
int Eps = real_number>
118 std::forward_iterator
auto line1,
120 using std::ranges::copy;
121 using std::ranges::subrange;
122 using std::views::reverse;
123 if (line0 == line1 || line0->empty() || line1->empty()) {
131 std::forward_iterator
auto line1,
137template <
typename Real, std::
size_t N>
147template <range_of_lines Lines,
floating_po
int Eps = real_number>
149 for (
auto line0 =
begin(lines); line0 !=
end(lines); ++line0) {
150 for (
auto line1 =
begin(lines); line1 !=
end(lines); ++line1) {
154 auto const is_empty = [](
auto const &l) {
return l.empty(); };
155 auto const [empty_begin, empty_end] = std::ranges::remove_if(lines, is_empty);
156 lines.erase(empty_begin, empty_end);
164template <range_of_lines Lines,
floating_po
int Eps = real_number>
165auto merge(Lines
const &unmerged_lines, Eps
const eps = 1e-13) {
166 using line_t = std::ranges::range_value_t<Lines>;
167 auto merged_lines = std::vector<std::vector<line_t>>(unmerged_lines.size());
169 auto unmerged_it =
begin(unmerged_lines);
170 for (
auto &merged_line : merged_lines) {
171 merged_line.push_back({*unmerged_it});
175 auto num_merge_steps =
176 static_cast<std::size_t
>(ceil(
log2(unmerged_lines.size())));
178 for (std::size_t i = 0; i < num_merge_steps; i++) {
181#pragma omp parallel for
182 for (std::size_t j = 0; j < unmerged_lines.size(); j += offset * 2) {
184 auto right = j + offset;
185 if (right < unmerged_lines.size()) {
187 merged_lines[left].reserve(
size(merged_lines[left]) +
188 size(merged_lines[right]));
189 std::ranges::move(merged_lines[right],
190 std::back_inserter(merged_lines[left]));
191 merged_lines[right].clear();
192 merged_lines[right].shrink_to_fit();
198 return merged_lines.front();
202template <range_of_lines Lines, floating_point Eps = real_number,
203 execution_policy_tag ExecutionPolicy>
204auto merge(Lines &lines, std::ranges::range_value_t<Lines> line_to_merge,
205 ExecutionPolicy
const tag, Eps
const eps = 1e-13) ->
auto & {
206 using namespace detail::line;
207 auto inserted = std::atomic_bool{
false};
208 auto mutex = std::mutex{};
210 std::vector<std::pair<std::ranges::iterator_t<Lines>, line_connection>>{};
214 determine_any_line_connection(line_to_merge, *line_it, eps);
215 if (connection != line_connection::no_connection) {
216 if constexpr (
is_same<ExecutionPolicy,
218 auto lock = std::lock_guard{mutex};
219 connections.emplace_back(line_it, connection);
221 connections.emplace_back(line_it, connection);
226 if (connections.empty()) {
227 lines.push_back(line_to_merge);
230 if (connections.size() == 1) {
231 auto const [line_it, connection] = connections.front();
232 connect_lines_if_possible(line_to_merge, *line_it, connection);
235 if (connections.size() == 2) {
236 auto const [line0_it, connection0] = connections[0];
237 auto const [line1_it, connection1] = connections[1];
238 connect_lines_if_possible(line_to_merge, *line0_it, connection0);
239 if (connect_lines_if_possible(*line1_it, *line0_it, eps)) {
240 lines.erase(line1_it);
Definition: concepts.h:30
auto determine_line_connection_cases(tatooine::line< Real, N > const &line0, tatooine::line< Real, N > const &line1, floating_point auto const eps)
Determines all line connection cases.
Definition: merge.h:20
auto determine_any_line_connection(tatooine::line< Real, N > const &line0, tatooine::line< Real, N > const &line1, floating_point auto const eps)
Determines all line connection cases.
Definition: merge.h:49
auto end(vertex_container< Real, NumDimensions, Handle > const &it)
Definition: vertex_container.h:46
line_connection
Definition: merge.h:10
@ common_back_front_common
@ front_common_front_common
@ common_back_common_back
@ front_common_common_back
auto begin(vertex_container< Real, NumDimensions, Handle > const &it)
Definition: vertex_container.h:41
auto next(const vertex_iterator< Real, NumDimensions, Handle > &it, size_t inc=1)
Definition: vertex_iterator.h:67
auto connect_lines_if_possible(tatooine::line< Real, N > &line0, tatooine::line< Real, N > &line1, line_connection const conn) -> bool
Definition: merge.h:71
Definition: algorithm.h:6
auto begin(Range &&range)
Definition: iterator_facade.h:318
constexpr auto pow(arithmetic auto const x)
Definition: math.h:30
constexpr auto approx_equal(T0 const &lhs, T1 const &rhs, common_type< tatooine::value_type< T0 >, tatooine::value_type< T1 > > eps=1e-6)
for comparison
Definition: tensor_utility.h:11
static constexpr auto is_same
Definition: type_traits.h:42
auto merge(Lines const &unmerged_lines, Eps const eps=1e-13)
Merges a set of lines and combines lines with equal vertex endings.
Definition: merge.h:165
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
constexpr auto log2(arithmetic auto const x)
Definition: math.h:24
constexpr auto for_loop(Iteration &&iteration, execution_policy::sequential_t, Ranges(&&... ranges)[2]) -> void
Use this function for creating a sequential nested loop.
Definition: for_loop.h:336
auto front_vertex() const -> auto const &
Definition: line.h:170
auto empty() const
Definition: line.h:140
auto back_vertex() const -> auto const &
Definition: line.h:173