From 86812fa5ddfc5fdbc181e3556bf3a111de5f4ea7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 5 Oct 2023 22:39:53 +0200 Subject: [PATCH] Fixed crash on macOS due to uninitialized variables, this happened when the wipe tower was not generated in the data for the conflict checker. The code was refactored to not use the extra FakeWipeTower class, all wipe tower related info is in Print::WipeTowerData object --- src/libslic3r/GCode/ConflictChecker.cpp | 111 +++++++++++++++++++++--- src/libslic3r/GCode/ConflictChecker.hpp | 2 +- src/libslic3r/Print.cpp | 94 ++------------------ src/libslic3r/Print.hpp | 44 +++------- 4 files changed, 121 insertions(+), 130 deletions(-) diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp index 8226c6c9ec..21a4e2dc08 100644 --- a/src/libslic3r/GCode/ConflictChecker.cpp +++ b/src/libslic3r/GCode/ConflictChecker.cpp @@ -94,6 +94,91 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance } } // namespace RasterizationImpl + + +static std::vector getFakeExtrusionPathsFromWipeTower(const WipeTowerData& wtd) +{ + float h = wtd.height; + float lh = wtd.first_layer_height; + int d = scale_(wtd.depth); + int w = scale_(wtd.width); + int bd = scale_(wtd.brim_width); + Point minCorner = { -wtd.brim_width, -wtd.brim_width }; + Point maxCorner = { minCorner.x() + w + bd, minCorner.y() + d + bd }; + float width = wtd.width; + float depth = wtd.depth; + float height = wtd.height; + float cone_angle = wtd.cone_angle; + const auto& z_and_depth_pairs = wtd.z_and_depth_pairs; + + const auto [cone_base_R, cone_scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle); + + std::vector paths; + for (float hh = 0.f; hh < h; hh += lh) { + + if (hh != 0.f) { + // The wipe tower may be getting smaller. Find the depth for this layer. + size_t i = 0; + for (i=0; i= z_and_depth_pairs[i].first && hh < z_and_depth_pairs[i+1].first) + break; + d = scale_(z_and_depth_pairs[i].second); + minCorner = {0.f, -d/2 + scale_(z_and_depth_pairs.front().second/2.f)}; + maxCorner = { minCorner.x() + w, minCorner.y() + d }; + } + + + ExtrusionPath path({ minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner }, + ExtrusionAttributes{ ExtrusionRole::WipeTower, ExtrusionFlow{ 0.0, 0.0, lh } }); + paths.push_back({ path }); + + // We added the border, now add several parallel lines so we can detect an object that is fully inside the tower. + // For now, simply use fixed spacing of 3mm. + for (coord_t y=minCorner.y()+scale_(3.); y 0.) { + path.polyline.clear(); + double r = cone_base_R * (1 - hh/height); + for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) + path.polyline.points.emplace_back(Point::new_scale(width/2. + r * std::cos(alpha)/cone_scale_x, depth/2. + r * std::sin(alpha))); + paths.back().emplace_back(path); + if (hh == 0.f) { // Cone brim. + for (float bw=wtd.brim_width; bw>0.f; bw-=3.f) { + path.polyline.clear(); + for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) // see load_wipe_tower_preview, where the same is a bit clearer + path.polyline.points.emplace_back(Point::new_scale( + width/2. + cone_base_R * std::cos(alpha)/cone_scale_x * (1. + cone_scale_x*bw/cone_base_R), + depth/2. + cone_base_R * std::sin(alpha) * (1. + bw/cone_base_R)) + ); + paths.back().emplace_back(path); + } + } + } + + // Only the first layer has brim. + if (hh == 0.f) { + minCorner = minCorner + Point(bd, bd); + maxCorner = maxCorner - Point(bd, bd); + } + } + + // Rotate and translate the tower into the final position. + for (ExtrusionPaths& ps : paths) { + for (ExtrusionPath& p : ps) { + p.polyline.rotate(Geometry::deg2rad(wtd.rotation_angle)); + p.polyline.translate(scale_(wtd.position.x()), scale_(wtd.position.y())); + } + } + + return paths; +} + + + void LinesBucketQueue::emplace_back_bucket(std::vector &&paths, const void *objPtr, Points offsets) { if (_objsPtrToId.find(objPtr) == _objsPtrToId.end()) { @@ -209,14 +294,20 @@ ConflictComputeOpt ConflictChecker::find_inter_of_lines(const LineWithIDs &lines } ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, - std::optional wtdptr) // find the first intersection point of lines in different objects + const WipeTowerData& wipe_tower_data) // find the first intersection point of lines in different objects { if (objs.empty() || (objs.size() == 1 && objs.front()->instances().size() == 1)) { return {}; } + // The code ported from BS uses void* to identify objects... + // Let's use the address of this variable to represent the wipe tower. + int wtptr = 0; + LinesBucketQueue conflictQueue; - if (wtdptr.has_value()) { // wipe tower at 0 by default - std::vector wtpaths = (*wtdptr)->getFakeExtrusionPathsFromWipeTower(); - conflictQueue.emplace_back_bucket(std::move(wtpaths), *wtdptr, Points{Point((*wtdptr)->plate_origin)}); + if (! wipe_tower_data.z_and_depth_pairs.empty()) { + // The wipe tower is being generated. + const Vec2d plate_origin = Vec2d::Zero(); + std::vector wtpaths = getFakeExtrusionPathsFromWipeTower(wipe_tower_data); + conflictQueue.emplace_back_bucket(std::move(wtpaths), &wtptr, Points{Point(plate_origin)}); } for (PrintObject *obj : objs) { std::pair, std::vector> layers = getAllLayersExtrusionPathsFromObject(obj); @@ -261,13 +352,11 @@ ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectP const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0].first._obj1); const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0].first._obj2); double conflictHeight = conflict[0].second; - if (wtdptr.has_value()) { - const FakeWipeTower* wtdp = *wtdptr; - if (ptr1 == wtdp || ptr2 == wtdp) { - if (ptr2 == wtdp) { std::swap(ptr1, ptr2); } - const PrintObject *obj2 = reinterpret_cast(ptr2); - return std::make_optional("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2); - } + if (ptr1 == &wtptr || ptr2 == &wtptr) { + assert(! wipe_tower_data.z_and_depth_pairs.empty()); + if (ptr2 == &wtptr) { std::swap(ptr1, ptr2); } + const PrintObject *obj2 = reinterpret_cast(ptr2); + return std::make_optional("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2); } const PrintObject *obj1 = reinterpret_cast(ptr1); const PrintObject *obj2 = reinterpret_cast(ptr2); diff --git a/src/libslic3r/GCode/ConflictChecker.hpp b/src/libslic3r/GCode/ConflictChecker.hpp index 0fee49ed0d..2d4e830dfb 100644 --- a/src/libslic3r/GCode/ConflictChecker.hpp +++ b/src/libslic3r/GCode/ConflictChecker.hpp @@ -124,7 +124,7 @@ using ConflictObjName = std::optional>; struct ConflictChecker { - static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional wtdptr); + static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, const WipeTowerData& wtd); static ConflictComputeOpt find_inter_of_lines(const LineWithIDs &lines); static ConflictComputeOpt line_intersect(const LineWithID &l1, const LineWithID &l2); }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index cbc9404e84..2264de546f 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1011,12 +1011,13 @@ void Print::process() this->set_done(psSkirtBrim); } - std::optional wipe_tower_opt = {}; if (this->has_wipe_tower()) { - m_fake_wipe_tower.set_pos_and_rotation({ m_config.wipe_tower_x, m_config.wipe_tower_y }, m_config.wipe_tower_rotation_angle); - wipe_tower_opt = std::make_optional(&m_fake_wipe_tower); + // These values have to be updated here, not during wipe tower generation. + // When the wipe tower is moved, it is not regenerated. + m_wipe_tower_data.position = { m_config.wipe_tower_x, m_config.wipe_tower_y }; + m_wipe_tower_data.rotation_angle = m_config.wipe_tower_rotation_angle; } - auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects, wipe_tower_opt); + auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects, m_wipe_tower_data); m_conflict_result = conflictRes; if (conflictRes.has_value()) @@ -1505,9 +1506,6 @@ void Print::_make_wipe_tower() // Initialize the wipe tower. WipeTower wipe_tower(m_config, m_default_region_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder()); - //wipe_tower.set_retract(); - //wipe_tower.set_zhop(); - // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i) wipe_tower.set_extruder(i, m_config); @@ -1576,10 +1574,9 @@ void Print::_make_wipe_tower() m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); - const Vec3d origin = Vec3d::Zero(); - m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_wipe_tower_height(), config().first_layer_height, m_wipe_tower_data.depth, - m_wipe_tower_data.z_and_depth_pairs, m_wipe_tower_data.brim_width, config().wipe_tower_rotation_angle, config().wipe_tower_cone_angle, {scale_(origin.x()), scale_(origin.y())}); - + m_wipe_tower_data.width = wipe_tower.width(); + m_wipe_tower_data.first_layer_height = config().first_layer_height; + m_wipe_tower_data.cone_angle = config().wipe_tower_cone_angle; } // Generate a recommended G-code output file name based on the format template, default extension, and template parameters @@ -1668,80 +1665,5 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co return final_path; } - std::vector FakeWipeTower::getFakeExtrusionPathsFromWipeTower() const - { - float h = height; - float lh = layer_height; - int d = scale_(depth); - int w = scale_(width); - int bd = scale_(brim_width); - Point minCorner = { -bd, -bd }; - Point maxCorner = { minCorner.x() + w + bd, minCorner.y() + d + bd }; - - const auto [cone_base_R, cone_scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle); - - std::vector paths; - for (float hh = 0.f; hh < h; hh += lh) { - - if (hh != 0.f) { - // The wipe tower may be getting smaller. Find the depth for this layer. - size_t i = 0; - for (i=0; i= z_and_depth_pairs[i].first && hh < z_and_depth_pairs[i+1].first) - break; - d = scale_(z_and_depth_pairs[i].second); - minCorner = {0.f, -d/2 + scale_(z_and_depth_pairs.front().second/2.f)}; - maxCorner = { minCorner.x() + w, minCorner.y() + d }; - } - - - ExtrusionPath path({ minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner }, - ExtrusionAttributes{ ExtrusionRole::WipeTower, ExtrusionFlow{ 0.0, 0.0, lh } }); - paths.push_back({ path }); - - // We added the border, now add several parallel lines so we can detect an object that is fully inside the tower. - // For now, simply use fixed spacing of 3mm. - for (coord_t y=minCorner.y()+scale_(3.); y 0.) { - path.polyline.clear(); - double r = cone_base_R * (1 - hh/height); - for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) - path.polyline.points.emplace_back(Point::new_scale(width/2. + r * std::cos(alpha)/cone_scale_x, depth/2. + r * std::sin(alpha))); - paths.back().emplace_back(path); - if (hh == 0.f) { // Cone brim. - for (float bw=brim_width; bw>0.f; bw-=3.f) { - path.polyline.clear(); - for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) // see load_wipe_tower_preview, where the same is a bit clearer - path.polyline.points.emplace_back(Point::new_scale( - width/2. + cone_base_R * std::cos(alpha)/cone_scale_x * (1. + cone_scale_x*bw/cone_base_R), - depth/2. + cone_base_R * std::sin(alpha) * (1. + bw/cone_base_R)) - ); - paths.back().emplace_back(path); - } - } - } - - // Only the first layer has brim. - if (hh == 0.f) { - minCorner = minCorner + Point(bd, bd); - maxCorner = maxCorner - Point(bd, bd); - } - } - - // Rotate and translate the tower into the final position. - for (ExtrusionPaths& ps : paths) { - for (ExtrusionPath& p : ps) { - p.polyline.rotate(Geometry::deg2rad(rotation_angle)); - p.polyline.translate(scale_(pos.x()), scale_(pos.y())); - } - } - - return paths; - } } // namespace Slic3r diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 8e55044531..7e5e5fecdf 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -439,38 +439,7 @@ private: FillLightning::GeneratorPtr m_lightning_generator; }; -struct FakeWipeTower -{ - // generate fake extrusion - Vec2f pos; - float width; - float height; - float layer_height; - float depth; - std::vector> z_and_depth_pairs; - float brim_width; - float rotation_angle; - float cone_angle; - Vec2d plate_origin; - void set_fake_extrusion_data(const Vec2f& p, float w, float h, float lh, float d, const std::vector>& zad, float bd, float ra, float ca, const Vec2d& o) - { - pos = p; - width = w; - height = h; - layer_height = lh; - depth = d; - z_and_depth_pairs = zad; - brim_width = bd; - rotation_angle = ra; - cone_angle = ca; - plate_origin = o; - } - - void set_pos_and_rotation(const Vec2f& p, float rotation) { pos = p; rotation_angle = rotation; } - - std::vector getFakeExtrusionPathsFromWipeTower() const; -}; struct WipeTowerData { @@ -491,6 +460,13 @@ struct WipeTowerData float brim_width; float height; + // Data needed to generate fake extrusions for conflict checking. + float width; + float first_layer_height; + float cone_angle; + Vec2d position; + float rotation_angle; + void clear() { priming.reset(nullptr); tool_changes.clear(); @@ -499,6 +475,11 @@ struct WipeTowerData number_of_toolchanges = -1; depth = 0.f; brim_width = 0.f; + width = 0.f; + first_layer_height = 0.f; + cone_angle = 0.f; + position = Vec2d::Zero(); + rotation_angle = 0.f; } private: @@ -740,7 +721,6 @@ private: friend class PrintObject; ConflictResultOpt m_conflict_result; - FakeWipeTower m_fake_wipe_tower; }; } /* slic3r_Print_hpp_ */