From fb2621c03ca264fa77106b20b4965a9d6d23c5ce Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Wed, 6 Apr 2022 09:57:36 +0200 Subject: [PATCH] Negative volumes raycasting fix - normal was flipped between iterations, incorrect algorithm for hit detection Debug files export fix after refactoring --- src/libslic3r/GCode/SeamPlacer.cpp | 43 +++++++++++++++++------------- src/libslic3r/GCode/SeamPlacer.hpp | 4 +-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 614ab4377..a53e3246e 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -146,13 +146,15 @@ std::vector raycast_visibility(const AABBTreeIndirect::Tree< std::vector result(triangles.indices.size()); tbb::parallel_for(tbb::blocked_range(0, result.size()), - [&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index, &raycasting_tree, &result](tbb::blocked_range r) { + [&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index, + &raycasting_tree, &result](tbb::blocked_range r) { // Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query. std::vector hits; for (size_t face_index = r.begin(); face_index < r.end(); ++face_index) { FaceVisibilityInfo &dest = result[face_index]; dest.visibility = 1.0f; - constexpr float decrease = 1.0f / (SeamPlacer::sqr_rays_per_triangle * SeamPlacer::sqr_rays_per_triangle); + constexpr float decrease = 1.0f + / (SeamPlacer::sqr_rays_per_triangle * SeamPlacer::sqr_rays_per_triangle); Vec3i face = triangles.indices[face_index]; Vec3f A = triangles.vertices[face.x()]; @@ -177,32 +179,35 @@ std::vector raycast_visibility(const AABBTreeIndirect::Tree< if (hit) { dest.visibility -= decrease; } - } else { - int in_negative = 0; - if (face_index >= negative_volumes_start_index) { // if casting from negative volume face, invert direction + } else { //TODO improve logic for order based boolean operations - consider order of volumes + Vec3d ray_origin_d = (center + normal * 0.1).cast(); // start above surface. + if (face_index >= negative_volumes_start_index) { // if casting from negative volume face, invert direction, change start pos final_ray_dir = -1.0 * final_ray_dir; - normal = -normal; + ray_origin_d = (center - normal * 0.1).cast(); } Vec3d final_ray_dir_d = final_ray_dir.cast(); - Vec3d ray_origin_d = (center + normal * 0.1).cast(); // start above surface. bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices, triangles.indices, raycasting_tree, ray_origin_d, final_ray_dir_d, hits); if (some_hit) { + int in_negative = 0; + int in_positive = 0; // NOTE: iterating in reverse, from the last hit for one simple reason: We know the state of the ray at that point; // It cannot be inside model, and it cannot be inside negative volume for (int hit_index = int(hits.size()) - 1; hit_index >= 0; --hit_index) { + Vec3f face_normal = its_face_normal(triangles, hits[hit_index].id); if (hits[hit_index].id >= int(negative_volumes_start_index)) { //negative volume hit - Vec3f normal = its_face_normal(triangles, hits[hit_index].id); - in_negative += sgn(normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space + in_negative += sgn(face_normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space // which in reverse hit analysis means, that we are entering negative space :) and vice versa - } else if (in_negative <= 0) { //object hit and we are not in negative space + } else { + in_positive += sgn(face_normal.dot(final_ray_dir)); + } + if (in_positive > 0 && in_negative <= 0) { dest.visibility -= decrease; break; } } } - } } } @@ -747,9 +752,9 @@ struct SeamComparator { ; #ifdef DEBUG_FILES -void debug_export_points(const std::vector> &object_perimter_points, +void debug_export_points(const std::vector &layers, const BoundingBox &bounding_box, std::string object_name, const SeamComparator &comparator) { - for (size_t layer_idx = 0; layer_idx < object_perimter_points.size(); ++layer_idx) { + for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { std::string angles_file_name = debug_out_path( (object_name + "_angles_" + std::to_string(layer_idx) + ".svg").c_str()); SVG angles_svg {angles_file_name, bounding_box}; @@ -759,7 +764,7 @@ void debug_export_points(const std::vector::min(); float max_weight = min_weight; - for (const SeamCandidate &point : object_perimter_points[layer_idx]) { + for (const SeamCandidate &point : layers[layer_idx].points) { Vec3i color = value_rgbi(-PI, PI, point.local_ccw_angle); std::string fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," + std::to_string(color.z()) + ")"; @@ -782,7 +787,7 @@ void debug_export_points(const std::vector &left, const std::pair &right) { @@ -1219,7 +1224,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: }; Vec3f color { randf(), randf(), randf() }; for (size_t i = 0; i < seam_string.size(); ++i) { - auto orig_seam = perimeter_points[seam_string[i].first][seam_string[i].second]; + auto orig_seam = layers[seam_string[i].first].points[seam_string[i].second]; fprintf(clusters, "v %f %f %f %f %f %f \n", orig_seam.position[0], orig_seam.position[1], orig_seam.position[2], color[0], color[1], @@ -1228,7 +1233,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: color = Vec3f { randf(), randf(), randf() }; for (size_t i = 0; i < seam_string.size(); ++i) { - Perimeter &perimeter = perimeter_points[seam_string[i].first][seam_string[i].second].perimeter; + const Perimeter &perimeter = layers[seam_string[i].first].points[seam_string[i].second].perimeter; fprintf(aligns, "v %f %f %f %f %f %f \n", perimeter.final_seam_position[0], perimeter.final_seam_position[1], perimeter.final_seam_position[2], color[0], color[1], @@ -1308,7 +1313,7 @@ void SeamPlacer::init(const Print &print) { } #ifdef DEBUG_FILES - debug_export_points(perimeter_points, po->bounding_box(), std::to_string(po->id().id), + debug_export_points(layers, po->bounding_box(), std::to_string(po->id().id), comparator); #endif } diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 04e6b1bc6..15dcd702a 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -119,7 +119,7 @@ public: static constexpr float polygon_local_angles_arm_distance = 0.5f; // increases angle importance at the cost of deacreasing visibility info importance. must be > 0 - static constexpr float additional_angle_importance = 0.3f; + static constexpr float additional_angle_importance = 0.6f; // If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer static constexpr float enforcer_blocker_distance_tolerance = 0.35f; @@ -134,7 +134,7 @@ public: // if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped. // this param limits the number of allowed skips static constexpr size_t seam_align_tolerable_skips = 4; - // minimum number of seams needed in cluster to make alignemnt happen + // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 6; // points covered by spline; determines number of splines for the given string static constexpr size_t seam_align_seams_per_segment = 8;