diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp index 8f36d65d96..a6a25fe6b3 100644 --- a/src/libslic3r/GCode/ConflictChecker.cpp +++ b/src/libslic3r/GCode/ConflictChecker.cpp @@ -89,10 +89,11 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance } } // namespace RasterizationImpl -void LinesBucketQueue::emplace_back_bucket(std::vector &&paths, PrintObject *objPtr, Point offset) +void LinesBucketQueue::emplace_back_bucket(std::vector &&paths, const void *objPtr, Point offset) { auto oldSize = _buckets.capacity(); - _buckets.emplace_back(std::move(paths), objPtr, offset); + _buckets.emplace_back(std::move(paths), _objsPtrToId.size(), offset); + _objsPtrToId.push_back(objPtr); _pq.push(&_buckets.back()); auto newSize = _buckets.capacity(); if (oldSize != newSize) { // pointers change @@ -199,10 +200,15 @@ ConflictRet ConflictChecker::find_inter_of_lines(const LineWithIDs &lines) return {}; } -ConflictRet ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs) // find the first intersection point of lines in different objects +ConflictObjName ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, + std::optional wtdptr) // find the first intersection point of lines in different objects { if (objs.size() <= 1) { return {}; } LinesBucketQueue conflictQueue; + if (wtdptr.has_value()) { // wipe tower at 0 by default + auto wtpaths = wtdptr.value()->getFakeExtrusionPathsFromWipeTower(); + conflictQueue.emplace_back_bucket(std::move(wtpaths), wtdptr.value(), {wtdptr.value()->plate_origin.x(),wtdptr.value()->plate_origin.y()}); + } for (PrintObject *obj : objs) { auto layers = getAllLayersExtrusionPathsFromObject(obj); conflictQueue.emplace_back_bucket(std::move(layers.first), obj, obj->instances().front().shift); @@ -219,7 +225,7 @@ ConflictRet ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs ob bool find = false; tbb::concurrent_vector conflict; - tbb::parallel_for(tbb::blocked_range( 0, layersLines.size()), [&](tbb::blocked_range range) { + tbb::parallel_for(tbb::blocked_range(0, layersLines.size()), [&](tbb::blocked_range range) { for (size_t i = range.begin(); i < range.end(); i++) { auto interRes = find_inter_of_lines(layersLines[i]); if (interRes.has_value()) { @@ -231,21 +237,33 @@ ConflictRet ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs ob }); if (find) { - return {conflict[0]}; + const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0]._obj1); + const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0]._obj2); + if (wtdptr.has_value()) { + const FakeWipeTower *wtdp = wtdptr.value(); + if (ptr1 == wtdp || ptr2 == wtdp) { + if (ptr2 == wtdp) { std::swap(ptr1, ptr2); } + const PrintObject *obj2 = reinterpret_cast(ptr2); + return {std::make_pair("WipeTower", obj2->model_object()->name)}; + } + } + const PrintObject *obj1 = reinterpret_cast(ptr1); + const PrintObject *obj2 = reinterpret_cast(ptr2); + return {std::make_pair(obj1->model_object()->name, obj2->model_object()->name)}; } else return {}; } ConflictRet ConflictChecker::line_intersect(const LineWithID &l1, const LineWithID &l2) { - if (l1._objPtr == l2._objPtr) { return {}; } // return true if lines are from same object + if (l1._id == l2._id) { return {}; } // return true if lines are from same object Point inter; bool intersect = l1._line.intersection(l2._line, &inter); if (intersect) { auto dist1 = std::min(unscale(Point(l1._line.a - inter)).norm(), unscale(Point(l1._line.b - inter)).norm()); auto dist2 = std::min(unscale(Point(l2._line.a - inter)).norm(), unscale(Point(l2._line.b - inter)).norm()); auto dist = std::min(dist1, dist2); - if (dist > 0.01) { return std::make_optional(l1._objPtr, l2._objPtr); } // the two lines intersects if dist>0.01mm + if (dist > 0.01) { return std::make_optional(l1._id, l2._id); } // the two lines intersects if dist>0.01mm } return {}; } diff --git a/src/libslic3r/GCode/ConflictChecker.hpp b/src/libslic3r/GCode/ConflictChecker.hpp index 0a0242e30f..c0cd4d214d 100644 --- a/src/libslic3r/GCode/ConflictChecker.hpp +++ b/src/libslic3r/GCode/ConflictChecker.hpp @@ -14,11 +14,11 @@ namespace Slic3r { struct LineWithID { - Line _line; - PrintObject *_objPtr; - int _role; + Line _line; + int _id; + int _role; - LineWithID(const Line &line, PrintObject *objPtr, int role) : _line(line), _objPtr(objPtr), _role(role) {} + LineWithID(const Line &line, int id, int role) : _line(line), _id(id), _role(role) {} }; using LineWithIDs = std::vector; @@ -30,11 +30,11 @@ private: unsigned _curPileIdx = 0; std::vector _piles; - PrintObject * _objPtr; + int _id; Point _offset; public: - LinesBucket(std::vector &&paths, PrintObject *objPtr, Point offset) : _piles(paths), _objPtr(objPtr), _offset(offset) {} + LinesBucket(std::vector &&paths, int id, Point offset) : _piles(paths), _id(id), _offset(offset) {} LinesBucket(LinesBucket &&) = default; bool valid() const { return _curPileIdx < _piles.size(); } @@ -52,9 +52,9 @@ public: for (const ExtrusionPath &path : _piles[_curPileIdx]) { if (path.is_force_no_extrusion() == false) { Polyline check_polyline = path.polyline; - if (path.role() != ExtrusionRole::erBrim) { check_polyline.translate(_offset); } + check_polyline.translate(_offset); Lines tmpLines = check_polyline.lines(); - for (const Line &line : tmpLines) { lines.emplace_back(line, _objPtr, path.role()); } + for (const Line &line : tmpLines) { lines.emplace_back(line, _id, path.role()); } } } return lines; @@ -75,11 +75,18 @@ class LinesBucketQueue private: std::vector _buckets; std::priority_queue, LinesBucketPtrComp> _pq; + std::vector _objsPtrToId; public: - void emplace_back_bucket(std::vector &&paths, PrintObject *objPtr, Point offset); - bool valid() const { return _pq.empty() == false; } - + void emplace_back_bucket(std::vector &&paths, const void *objPtr, Point offset); + bool valid() const { return _pq.empty() == false; } + const void *idToObjsPtr(int id) + { + if (id >= 0 && id < _objsPtrToId.size()) { + return _objsPtrToId[id]; + } else + return nullptr; + } void removeLowests(); LineWithIDs getCurLines() const; }; @@ -94,21 +101,21 @@ std::pair, std::vector> getAllLayers struct ConflictResult { - PrintObject *_obj1; - PrintObject *_obj2; - ConflictResult(PrintObject *obj1, PrintObject *obj2) : _obj1(obj1), _obj2(obj2) {} + int _obj1; + int _obj2; + ConflictResult(int obj1, int obj2) : _obj1(obj1), _obj2(obj2) {} ConflictResult() = default; }; -static_assert(std::is_trivial::value, "atomic value requires to be trival."); - using ConflictRet = std::optional; +using ConflictObjName = std::optional>; + struct ConflictChecker { - static ConflictRet find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs); - static ConflictRet find_inter_of_lines(const LineWithIDs &lines); - static ConflictRet line_intersect(const LineWithID &l1, const LineWithID &l2); + static ConflictObjName find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional wtdptr); + static ConflictRet find_inter_of_lines(const LineWithIDs &lines); + static ConflictRet line_intersect(const LineWithID &l1, const LineWithID &l2); }; } // namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 0c4175cc6b..dec8887019 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -156,6 +156,8 @@ public: float get_depth() const { return m_wipe_tower_depth; } float get_brim_width() const { return m_wipe_tower_brim_width_real; } + float get_height() const { return m_wipe_tower_height; } + float get_layer_height() const { return m_layer_height; } void set_last_layer_extruder_fill(bool extruder_fill) { if (!m_plan.empty()) { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 5a327ee3ba..dc1f4d4fe0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1679,15 +1679,18 @@ void Print::process(bool use_cache) { using Clock = std::chrono::high_resolution_clock; auto startTime = Clock::now(); - auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects); + std::optional wipe_tower_opt = {}; + if (this->has_wipe_tower()) { + m_fake_wipe_tower.set_pos({m_config.wipe_tower_x.get_at(m_plate_index), m_config.wipe_tower_y.get_at(m_plate_index)}); + wipe_tower_opt = std::make_optional(&m_fake_wipe_tower); + } + auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects, wipe_tower_opt); auto endTime = Clock::now(); volatile double seconds = std::chrono::duration_cast(endTime - startTime).count() / (double) 1000; BOOST_LOG_TRIVIAL(info) << "gcode path conflicts check takes " << seconds << " secs."; if (conflictRes.has_value()) { - m_conflict_result.set(conflictRes.value()._obj1, conflictRes.value()._obj2); - auto objName1 = conflictRes.value()._obj1->m_model_object->name; - auto objName2 = conflictRes.value()._obj2->m_model_object->name; + m_conflict_result.set(conflictRes.value().first, conflictRes.value().second); } else { m_conflict_result.reset(); } @@ -1723,7 +1726,7 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor gcode.do_export(this, path.c_str(), result, thumbnail_cb); //BBS if (m_conflict_result.conflicted) { - result->conflict_result.set(m_conflict_result.obj1->m_model_object->name, m_conflict_result.obj2->m_model_object->name); + result->conflict_result.set(m_conflict_result.obj1, m_conflict_result.obj2); } else { result->conflict_result.reset(); } @@ -2152,8 +2155,11 @@ void Print::_make_wipe_tower() m_wipe_tower_data.final_purge = Slic3r::make_unique( wipe_tower.tool_change((unsigned int)(-1))); - m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); + 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 = this->get_plate_origin(); + m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_height(), wipe_tower.get_layer_height(), m_wipe_tower_data.depth, + m_wipe_tower_data.brim_width, {scale_(origin.x()), scale_(origin.y())}); } // Generate a recommended G-code output file name based on the format template, default extension, and template parameters diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ef43affa10..0e5e9c368b 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -510,6 +510,58 @@ private: static bool infill_only_where_needed; }; +struct FakeWipeTower +{ + // generate fake extrusion + Vec2f pos; + float width; + float height; + float layer_height; + float depth; + float brim_width; + Vec2d plate_origin; + + void set_fake_extrusion_data(Vec2f p, float w, float h, float lh, float d, float bd, Vec2d o) + { + pos = p; + width = w; + height = h; + layer_height = lh; + depth = d; + brim_width = bd; + plate_origin = o; + } + + void set_pos(Vec2f p) { pos = p; } + + std::vector getFakeExtrusionPathsFromWipeTower() const + { + float h = height; + float lh = layer_height; + int d = scale_(depth); + int w = scale_(width); + int bd = scale_(brim_width); + Point minCorner = {scale_(pos.x()), scale_(pos.y())}; + Point maxCorner = {minCorner.x() + w, minCorner.y() + d}; + + std::vector paths; + for (float hh = 0.f; hh < h; hh += lh) { + ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, lh); + path.polyline = {minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner}; + paths.push_back({path}); + + if (hh == 0.f) { // add brim + ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, lh); + Point wtbminCorner = {minCorner - Point{bd, bd}}; + Point wtbmaxCorner = {maxCorner + Point{bd, bd}}; + fakeBrim.polyline = {wtbminCorner, {wtbmaxCorner.x(), wtbminCorner.y()}, wtbmaxCorner, {wtbminCorner.x(), wtbmaxCorner.y()}, wtbminCorner}; + paths.back().push_back(fakeBrim); + } + } + return paths; + } +}; + struct WipeTowerData { // Following section will be consumed by the GCodeGenerator. @@ -779,12 +831,12 @@ private: struct ConflictResult { bool conflicted; - PrintObject *obj1; - PrintObject *obj2; + std::string obj1; + std::string obj2; //TODO //the actual loaction - void set(PrintObject *o1, PrintObject *o2) + void set(const std::string& o1, const std::string& o2) { conflicted = true; obj1 = o1; @@ -793,10 +845,11 @@ private: void reset() { conflicted = false; - obj1 = nullptr; - obj2 = nullptr; + obj1.clear(); + obj2.clear(); } }m_conflict_result; + FakeWipeTower m_fake_wipe_tower; // To allow GCode to set the Print's GCodeExport step status. friend class GCode;