From 53ff4a69e009ef2076a22a26055a2311973e6525 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Tue, 22 Feb 2022 13:53:24 +0100 Subject: [PATCH] implemented debug files export --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/GCode/SeamPlacerNG.cpp | 64 ++++++++ src/libslic3r/GCode/SeamPlacerNG.hpp | 2 +- src/libslic3r/GCode/Subdivide.cpp | 218 +++++++++++++++++++++++++++ src/libslic3r/GCode/Subdivide.hpp | 12 ++ 5 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 src/libslic3r/GCode/Subdivide.cpp create mode 100644 src/libslic3r/GCode/Subdivide.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 16af2bfdc..6e0679291 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -120,6 +120,8 @@ set(SLIC3R_SOURCES GCode/SpiralVase.hpp GCode/SeamPlacerNG.cpp GCode/SeamPlacerNG.hpp + GCode/Subdivide.hpp + GCode/Subdivide.cpp GCode/ToolOrdering.cpp GCode/ToolOrdering.hpp GCode/WipeTower.cpp diff --git a/src/libslic3r/GCode/SeamPlacerNG.cpp b/src/libslic3r/GCode/SeamPlacerNG.cpp index 366bb4b6c..98347d49c 100644 --- a/src/libslic3r/GCode/SeamPlacerNG.cpp +++ b/src/libslic3r/GCode/SeamPlacerNG.cpp @@ -15,6 +15,13 @@ #include "libslic3r/SVG.hpp" #include "libslic3r/Layer.hpp" +#define DEBUG_FILES + +#ifdef DEBUG_FILES +#include "Subdivide.hpp" +#include +#endif + namespace Slic3r { namespace SeamPlacerImpl { @@ -253,6 +260,58 @@ struct GlobalModelInfo { return visibility; } + +#ifdef DEBUG_FILES + void debug_export(const indexed_triangle_set &obj_mesh, const char *file_name) const { + indexed_triangle_set divided_mesh = subdivide(obj_mesh, 3); + Slic3r::CNumericLocalesSetter locales_setter; + { + FILE *fp = boost::nowide::fopen(file_name, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) + << "stl_write_obj: Couldn't open " << file_name << " for writing"; + return; + } + + const auto vis_to_rgb = [](float normalized_visibility) { + float ratio = 2 * normalized_visibility; + float blue = std::max(0.0f, 1.0f - ratio); + float red = std::max(0.0f, ratio - 1.0f); + float green = std::max(0.0f, 1.0f - blue - red); + return Vec3f { red, blue, green }; + }; + + for (size_t i = 0; i < divided_mesh.vertices.size(); ++i) { + float visibility = calculate_point_visibility(divided_mesh.vertices[i], + sqrt(hits_area_to_consider / float(PI))); + float normalized = visibility / SeamPlacer::expected_hits_per_area; + Vec3f color = vis_to_rgb(normalized); + fprintf(fp, "v %f %f %f %f %f %f\n", + divided_mesh.vertices[i](0), divided_mesh.vertices[i](1), divided_mesh.vertices[i](2), + color(0), color(1), color(2) + ); + } + for (size_t i = 0; i < divided_mesh.indices.size(); ++i) + fprintf(fp, "f %d %d %d\n", divided_mesh.indices[i][0] + 1, divided_mesh.indices[i][1] + 1, + divided_mesh.indices[i][2] + 1); + fclose(fp); + } + { + auto fname = std::string("hits_").append(file_name); + FILE *fp = boost::nowide::fopen(fname.c_str(), "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) + << "Couldn't open " << fname << " for writing"; + } + + for (size_t i = 0; i < geometry_raycast_hits.size(); ++i) + fprintf(fp, "v %f %f %f \n", geometry_raycast_hits[i].position[0], geometry_raycast_hits[i].position[1], + geometry_raycast_hits[i].position[2]); + fclose(fp); + } + } +#endif + } ; @@ -422,6 +481,11 @@ void gather_global_model_info(GlobalModelInfo &result, const PrintObject *po) { BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: end"; + +#ifdef DEBUG_FILES + auto filename = "visiblity_of_" + std::to_string(po->id().id) + ".obj"; + result.debug_export(triangle_set, filename.c_str()); +#endif } struct DefaultSeamComparator { diff --git a/src/libslic3r/GCode/SeamPlacerNG.hpp b/src/libslic3r/GCode/SeamPlacerNG.hpp index ce69fcf12..dfd320d91 100644 --- a/src/libslic3r/GCode/SeamPlacerNG.hpp +++ b/src/libslic3r/GCode/SeamPlacerNG.hpp @@ -82,7 +82,7 @@ public: using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; static constexpr float expected_hits_per_area = 100.0f; - static constexpr size_t ray_count = 150000; //NOTE: fixed count of rays is better: + static constexpr size_t ray_count = 1500000; //NOTE: fixed count of rays is better: // on small models, the visibility has huge impact and precision is welcomed. // on large models, it would be very expensive to get similar results, and the local effect is arguably less important. static constexpr float cosine_hemisphere_sampling_power = 1.5f; diff --git a/src/libslic3r/GCode/Subdivide.cpp b/src/libslic3r/GCode/Subdivide.cpp new file mode 100644 index 000000000..734b1147d --- /dev/null +++ b/src/libslic3r/GCode/Subdivide.cpp @@ -0,0 +1,218 @@ +#include "Subdivide.hpp" +#include "Point.hpp" + +namespace Slic3r{ + +indexed_triangle_set subdivide( + const indexed_triangle_set &its, float max_length) +{ + // same order as key order in Edge Divides + struct VerticesSequence + { + size_t start_index; + bool positive_order; + VerticesSequence(size_t start_index, bool positive_order = true) + : start_index(start_index), positive_order(positive_order){} + }; + // vertex index small, big vertex index from key.first to key.second + using EdgeDivides = std::map, VerticesSequence>; + struct Edges + { + Vec3f data[3]; + Vec3f lengths; + Edges(const Vec3crd &indices, const std::vector &vertices) + : lengths(-1.f,-1.f,-1.f) + { + const Vec3f &v0 = vertices[indices[0]]; + const Vec3f &v1 = vertices[indices[1]]; + const Vec3f &v2 = vertices[indices[2]]; + data[0] = v0 - v1; + data[1] = v1 - v2; + data[2] = v2 - v0; + } + float abs_sum(const Vec3f &v) + { + return abs(v[0]) + abs(v[1]) + abs(v[2]); + } + bool is_dividable(const float& max_length) { + Vec3f sum(abs_sum(data[0]), abs_sum(data[1]), abs_sum(data[2])); + Vec3i biggest_index = (sum[0] > sum[1]) ? + ((sum[0] > sum[2]) ? + ((sum[2] > sum[1]) ? + Vec3i(0, 2, 1) : + Vec3i(0, 1, 2)) : + Vec3i(2, 0, 1)) : + ((sum[1] > sum[2]) ? + ((sum[2] > sum[0]) ? + Vec3i(1, 2, 0) : + Vec3i(1, 0, 2)) : + Vec3i(2, 1, 0)); + for (int i = 0; i < 3; i++) { + int index = biggest_index[i]; + if (sum[index] <= max_length) return false; + lengths[index] = data[index].norm(); + if (lengths[index] <= max_length) continue; + + // calculate rest of lengths + for (int j = i + 1; j < 3; j++) { + index = biggest_index[j]; + lengths[index] = data[index].norm(); + } + return true; + } + return false; + } + }; + struct TriangleLengths + { + Vec3crd indices; + Vec3f l; // lengths + TriangleLengths(const Vec3crd &indices, const Vec3f &lengths) + : indices(indices), l(lengths) + {} + + int get_divide_index(float max_length) { + if (l[0] > l[1] && l[0] > l[2]) { + if (l[0] > max_length) return 0; + } else if (l[1] > l[2]) { + if (l[1] > max_length) return 1; + } else { + if (l[2] > max_length) return 2; + } + return -1; + } + + // divide triangle add new vertex to vertices + std::pair divide( + int divide_index, float max_length, + std::vector &vertices, + EdgeDivides &edge_divides) + { + // index to lengths and indices + size_t i0 = divide_index; + size_t i1 = (divide_index + 1) % 3; + size_t vi0 = indices[i0]; + size_t vi1 = indices[i1]; + std::pair key(vi0, vi1); + bool key_swap = false; + if (key.first > key.second) { + std::swap(key.first, key.second); + key_swap = true; + } + + float length = l[divide_index]; + size_t count_edge_vertices = static_cast(floor(length / max_length)); + float count_edge_segments = static_cast(count_edge_vertices + 1); + + auto it = edge_divides.find(key); + if (it == edge_divides.end()) { + // Create new vertices + VerticesSequence new_vs(vertices.size()); + Vec3f vf = vertices[key.first]; // copy + const Vec3f &vs = vertices[key.second]; + Vec3f dir = vs - vf; + for (size_t i = 1; i <= count_edge_vertices; ++i) { + float ratio = i / count_edge_segments; + vertices.push_back(vf + dir * ratio); + } + bool success; + std::tie(it,success) = edge_divides.insert({key, new_vs}); + assert(success); + } + const VerticesSequence &vs = it->second; + + int index_offset = count_edge_vertices/2; + size_t i2 = (divide_index + 2) % 3; + if (count_edge_vertices % 2 == 0 && key_swap == l[i1] < l[i2]) { + --index_offset; + } + int sign = (vs.positive_order) ? 1 : -1; + size_t new_index = vs.start_index + sign*index_offset; + + size_t vi2 = indices[i2]; + const Vec3f &v2 = vertices[vi2]; + Vec3f new_edge = v2 - vertices[new_index]; + float new_len = new_edge.norm(); + + float ratio = (1 + index_offset) / count_edge_segments; + float len1 = l[i0] * ratio; + float len2 = l[i0] - len1; + if (key_swap) std::swap(len1, len2); + + Vec3crd indices1(vi0, new_index, vi2); + Vec3f lengths1(len1, new_len, l[i2]); + + Vec3crd indices2(new_index, vi1, vi2); + Vec3f lengths2(len2, l[i1], new_len); + + // append key for divided edge when neccesary + if (index_offset > 0) { + std::pair new_key(key.first, new_index); + bool new_key_swap = false; + if (new_key.first > new_key.second) { + std::swap(new_key.first, new_key.second); + new_key_swap = true; + } + if (edge_divides.find(new_key) == edge_divides.end()) { + // insert new + edge_divides.insert({new_key, (new_key_swap) ? + VerticesSequence(new_index - sign, !vs.positive_order) + : vs}); + } + } + + if (index_offset < count_edge_vertices-1) { + std::pair new_key(new_index, key.second); + bool new_key_swap = false; + if (new_key.first > new_key.second) { + std::swap(new_key.first, new_key.second); + new_key_swap = true; + } + // bad order + if (edge_divides.find(new_key) == edge_divides.end()) { + edge_divides.insert({new_key, (new_key_swap) ? + VerticesSequence(vs.start_index + sign*(count_edge_vertices-1), !vs.positive_order) + : VerticesSequence(new_index + sign, vs.positive_order)}); + } + } + + return {TriangleLengths(indices1, lengths1), + TriangleLengths(indices2, lengths2)}; + } + }; + indexed_triangle_set result; + result.indices.reserve(its.indices.size()); + const std::vector &vertices = its.vertices; + result.vertices = vertices; // copy + std::queue tls; + + EdgeDivides edge_divides; + for (const Vec3crd &indices : its.indices) { + Edges edges(indices, vertices); + // speed up only sum not sqrt is apply + if (!edges.is_dividable(max_length)) { + // small triangle + result.indices.push_back(indices); + continue; + } + TriangleLengths tl(indices, edges.lengths); + do { + int divide_index = tl.get_divide_index(max_length); + if (divide_index < 0) { + // no dividing + result.indices.push_back(tl.indices); + if (tls.empty()) break; + tl = tls.front(); // copy + tls.pop(); + } else { + auto [tl1, tl2] = tl.divide(divide_index, max_length, + result.vertices, edge_divides); + tl = tl1; + tls.push(tl2); + } + } while (true); + } + return result; +} + +} diff --git a/src/libslic3r/GCode/Subdivide.hpp b/src/libslic3r/GCode/Subdivide.hpp new file mode 100644 index 000000000..3f6f96d17 --- /dev/null +++ b/src/libslic3r/GCode/Subdivide.hpp @@ -0,0 +1,12 @@ +#ifndef libslic3r_Subdivide_hpp_ +#define libslic3r_Subdivide_hpp_ + +#include "TriangleMesh.hpp" + +namespace Slic3r { + +indexed_triangle_set subdivide(const indexed_triangle_set &its, float max_length); + +} + +#endif //libslic3r_Subdivide_hpp_