1#ifndef TATOOINE_DETAIL_LINE_OPERATIONS_H
2#define TATOOINE_DETAIL_LINE_OPERATIONS_H
10template <
typename T,
typename Writer,
typename Names>
13 std::vector<T> prop_collector;
14 for (
auto const& [name_to_search, type_to_search] : names) {
15 prop_collector.clear();
16 for (
auto const& l : lines) {
17 if (l.has_vertex_property(name_to_search)) {
19 auto const& prop = l.template vertex_property<T>(name_to_search);
20 std::ranges::copy(prop.internal_container(),
21 std::back_inserter(prop_collector));
23 for (std::size_t i = 0; i < l.vertices().
size(); ++i) {
24 prop_collector.push_back(nan<T>());
29 writer.write_scalars(name_to_search, prop_collector);
37template <range_of_lines Lines>
38auto write_vtp(Lines
const& lines, filesystem::path
const& path) ->
void {
39 auto file = std::ofstream{path, std::ios::binary};
40 if (!file.is_open()) {
41 throw std::runtime_error{
"Could not write " + path.string()};
43 auto offset = std::size_t{};
44 using header_type = std::uint32_t;
45 using connectivity_int_t = std::int32_t;
46 using offset_int_t = connectivity_int_t;
47 using real_type =
typename Lines::value_type::real_type;
49 <<
" type=\"PolyData\""
50 <<
" version=\"1.0\" "
51 "byte_order=\"LittleEndian\""
53 << vtk::xml::to_data_type<header_type>()
55 file <<
" <PolyData>\n";
56 for (
auto const& l : lines) {
58 <<
" NumberOfPoints=\"" << l.vertices().size() <<
"\""
59 <<
" NumberOfPolys=\"0\""
60 <<
" NumberOfVerts=\"0\""
61 <<
" NumberOfLines=\""
62 << (l.vertices().size() - (l.is_closed() ? 0 : 1)) <<
"\""
63 <<
" NumberOfStrips=\"0\""
67 file <<
" <Points>\n";
69 <<
" format=\"appended\""
70 <<
" offset=\"" << offset <<
"\""
73 vtk::xml::to_data_type<real_type>())
74 <<
"\" NumberOfComponents=\"3\"/>\n";
75 auto const num_bytes_points =
76 header_type(
sizeof(
real_type) * 3 * l.vertices().size());
77 offset += num_bytes_points +
sizeof(header_type);
78 file <<
" </Points>\n";
83 file <<
" <DataArray format=\"appended\" offset=\"" << offset
86 vtk::xml::to_data_type<connectivity_int_t>())
87 <<
"\" Name=\"connectivity\"/>\n";
88 auto const num_bytes_connectivity =
89 (l.vertices().size() - (l.is_closed() ? 0 : 1)) * 2 *
90 sizeof(connectivity_int_t);
91 offset += num_bytes_connectivity +
sizeof(header_type);
93 file <<
" <DataArray format=\"appended\" offset=\"" << offset
96 vtk::xml::to_data_type<offset_int_t>())
97 <<
"\" Name=\"offsets\"/>\n";
98 auto const num_bytes_offsets =
99 sizeof(offset_int_t) * (l.vertices().size() - (l.is_closed() ? 0 : 1));
100 offset += num_bytes_offsets +
sizeof(header_type);
101 file <<
" </Lines>\n";
102 file <<
" </Piece>\n";
104 file <<
" </PolyData>\n";
105 file <<
" <AppendedData encoding=\"raw\">\n _";
107 for (
auto const& l : lines) {
108 auto arr_size = header_type{};
109 arr_size = header_type(
sizeof(
real_type) * 3 * l.vertices().size());
110 file.write(
reinterpret_cast<char const*
>(&arr_size),
sizeof(header_type));
112 for (
auto const v : l.vertices()) {
113 if constexpr (Lines::value_type::num_dimensions() == 2) {
114 file.write(
reinterpret_cast<char const*
>(l.at(v).data()),
116 file.write(
reinterpret_cast<char const*
>(&zero),
sizeof(
real_type));
117 }
else if constexpr (Lines::value_type::num_dimensions() == 3) {
118 file.write(
reinterpret_cast<char const*
>(l.at(v).data()),
125 auto connectivity_data = std::vector<connectivity_int_t>{};
126 connectivity_data.reserve(
127 (l.vertices().size() - (l.is_closed() ? 0 : 1)) * 2);
128 for (std::size_t i = 0; i < l.vertices().size() - 1; ++i) {
129 connectivity_data.push_back(
static_cast<connectivity_int_t
>(i));
130 connectivity_data.push_back(
static_cast<connectivity_int_t
>(i + 1));
133 connectivity_data.push_back(
134 static_cast<connectivity_int_t
>(l.vertices().size()) - 1);
135 connectivity_data.push_back(0);
137 arr_size =
static_cast<header_type
>(connectivity_data.size() *
138 sizeof(connectivity_int_t));
139 file.write(
reinterpret_cast<char const*
>(&arr_size),
sizeof(header_type));
140 file.write(
reinterpret_cast<char const*
>(connectivity_data.data()),
146 auto offsets = std::vector<offset_int_t>(
147 l.vertices().size() - (l.is_closed() ? 0 : 1), 2);
148 for (std::size_t i = 1; i <
size(offsets); ++i) {
149 offsets[i] += offsets[i - 1];
151 arr_size =
static_cast<header_type
>(
sizeof(offset_int_t)) *
152 static_cast<header_type
>(l.vertices().size() -
153 static_cast<header_type
>((l.is_closed() ? 0 : 1)));
154 file.write(
reinterpret_cast<char const*
>(&arr_size),
sizeof(header_type));
155 file.write(
reinterpret_cast<char const*
>(offsets.data()), arr_size);
158 file <<
"\n </AppendedData>\n";
159 file <<
"</VTKFile>";
162template <range_of_lines Lines>
163auto write_vtk(Lines
const& lines, filesystem::path
const& path,
164 std::string
const& title =
"tatooine lines") ->
void {
166 if (writer.is_open()) {
167 auto num_pts = std::size_t{};
168 for (
const auto& l : lines) {
169 num_pts += l.vertices().size();
172 std::vector<std::array<typename Lines::value_type::real_type, 3>>{};
173 auto line_seqs = std::vector<std::vector<std::size_t>>{};
174 points.reserve(num_pts);
175 line_seqs.reserve(lines.size());
177 auto cur_first = std::size_t{};
178 for (
const auto& l : lines) {
180 for (
const auto& v : l.vertices()) {
181 auto const& p = l[v];
182 if constexpr (Lines::value_type::num_dimensions() == 3) {
183 points.push_back({p(0), p(1), p(2)});
185 points.push_back({p(0), p(1), 0});
190 boost::iota(line_seqs.emplace_back(l.vertices().size()), cur_first);
192 line_seqs.back().push_back(cur_first);
194 cur_first += l.vertices().size();
198 writer.set_title(title);
199 writer.write_header();
200 writer.write_points(points);
201 writer.write_lines(line_seqs);
202 writer.write_point_data(num_pts);
204 auto names = std::set<std::pair<std::string, std::type_info const*>>{};
206 for (
const auto& l : lines) {
207 for (
auto const& [name, prop] : l.vertex_properties()) {
208 names.insert(std::pair{name, &prop->type()});
211 detail::line::write_properties_to_vtk<double>(writer, names,
217template <range_of_lines Lines>
218auto write(Lines
const& lines, filesystem::path
const& path) ->
void {
219 using line_t = std::ranges::range_value_t<Lines>;
220 auto const ext = path.extension();
221 if constexpr (line_t::num_dimensions() == 2 ||
222 line_t::num_dimensions() == 3) {
226 }
else if (ext ==
".vtp") {
231 throw std::runtime_error(
"Could not write lines. Unknown file extension: \"" +
232 ext.string() +
"\".");
235template <
typename Lines,
typename MaxDist>
237 using line_t = std::ranges::range_value_t<Lines>;
238 auto merged = std::list<line_t> {};
239 merged.emplace_back(std::move(lines.back()));
242 while (!lines.empty()) {
243 auto min_d = std::numeric_limits<typename line_t::real_type>::max();
244 auto best_it = std::end(lines);
245 auto merged_take_front =
false;
246 auto it_take_front =
false;
247 for (
auto it = std::begin(lines); it != std::end(lines); ++it) {
249 distance(merged.back().front_vertex(), it->front_vertex());
250 d < min_d && d < max_length) {
253 merged_take_front =
true;
254 it_take_front =
true;
257 distance(merged.back().back_vertex(), it->front_vertex());
258 d < min_d && d < max_length) {
261 merged_take_front =
false;
262 it_take_front =
true;
265 distance(merged.back().front_vertex(), it->back_vertex());
266 d < min_d && d < max_length) {
269 merged_take_front =
true;
270 it_take_front =
false;
273 distance(merged.back().back_vertex(), it->back_vertex());
274 d < min_d && d < max_length) {
277 merged_take_front =
false;
278 it_take_front =
false;
282 if (best_it !=
end(lines)) {
283 if (merged_take_front) {
285 for (
const auto& v : best_it->vertices()) {
286 merged.back().push_front(v);
290 best_it->vertices() | boost::adaptors::reversed) {
291 merged.back().push_front(v);
296 for (
const auto& v : best_it->vertices()) {
297 merged.back().push_back(v);
301 best_it->vertices() | boost::adaptors::reversed) {
302 merged.back().push_back(v);
306 lines.erase(best_it);
308 merged.emplace_back(std::move(lines.back()));
319 std::vector<
typename std::decay_t<
decltype(lines)>
::value_type>{};
320 for (
auto const& l : lines) {
321 if (l.arc_length() > max_length) {
322 filtered.push_back(l);
328template <
typename Real>
331 static auto const eps = Real(1e-6);
332 auto xs = std::vector<vec<Real, 2>>{};
333 for (
auto const& l0 : lines0) {
334 for (
auto const& l1 : lines1) {
335 for (std::size_t i = 0; i < l0.vertices().
size() - 1; ++i) {
336 for (std::size_t j = 0; j < l1.vertices().
size() - 1; ++j) {
337 auto const& p0 = l0.vertex_at(i);
338 auto const& p1 = l0.vertex_at(i + 1);
339 auto const& p2 = l1.vertex_at(j);
340 auto const& p3 = l1.vertex_at(j + 1);
341 auto const d01 = p0 - p1;
342 auto const d23 = p2 - p3;
343 auto const d02 = p0 - p2;
345 auto const denom = d01.x() * d23.y() - d01.y() * d23.x();
346 if (std::abs(denom) < eps) {
349 auto const inv_denom = 1 / denom;
351 auto const nom_t = d02.x() * d23.y() - d02.y() * d23.x();
352 auto const t = nom_t * inv_denom;
353 if (0 > t || t > 1) {
356 auto const nom_u = -(d01.x() * d02.y() - d01.y() * d02.x());
357 auto const u = nom_u * inv_denom;
358 if (0 > u || u > 1) {
361 xs.push_back(p2 - u * d23);
Definition: vtk_legacy.h:448
Definition: concepts.h:33
auto write_properties_to_vtk(Writer &writer, Names const &names, range_of_lines auto const &lines) -> void
Definition: write.h:11
auto to_string(data_type const t) -> std::string_view
Definition: algorithm.h:6
constexpr auto distance(Iter const &it0, Iter const &it1)
Definition: iterator_facade.h:372
auto write_vtk(Lines const &lines, filesystem::path const &path, std::string const &title="tatooine lines") -> void
Definition: write.h:163
typename value_type_impl< T >::type value_type
Definition: type_traits.h:280
auto end(Range &&range)
Definition: iterator_facade.h:322
auto write(Lines const &lines, filesystem::path const &path) -> void
Definition: write.h:218
auto intersections(std::vector< line< Real, 2 > > const &lines0, std::vector< line< Real, 2 > > const &lines1)
Definition: write.h:329
auto write_vtp(Lines const &lines, filesystem::path const &path) -> void
Definition: write.h:38
auto filter_length(range_of_lines auto const &lines, arithmetic auto const max_length)
Definition: write.h:316
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