diff --git a/resources/ui_layout/example/freq_fff.ui b/resources/ui_layout/example/freq_fff.ui index a74cc590ca5..f937b56fdb2 100644 --- a/resources/ui_layout/example/freq_fff.ui +++ b/resources/ui_layout/example/freq_fff.ui @@ -13,3 +13,9 @@ group:freq_settings_event:no_title:no_search: setting:simple:script:bool:depends$brim_width:label$Brim:tooltip$Set the brim. Will be set to 5mm if nothing was previously set.:s_brim freq_purging_volumes end_line + line: + setting:simple:script:enum$hot$Hot$mild$Mild$cold$Cold:depends$bed_temperature$first_layer_bed_temperature:label$Bed temp:tooltip$Choose the bed you want.:full_width:s_bed_temp_fff + end_line + line: + setting:simple:script:enum$normal$Default$45$45°$custom$Custom:depends$init_z_rotate:label$Import angle:tooltip$The angle at which the parts are imported:full_width:s_orientation_fff + end_line diff --git a/resources/ui_layout/example/print.as b/resources/ui_layout/example/print.as index 775cac03e12..a4375b3bcbb 100644 --- a/resources/ui_layout/example/print.as +++ b/resources/ui_layout/example/print.as @@ -412,3 +412,55 @@ void s_noperi_set(string &out set_val, int idx) if (idx == 0) set_int("no_perimeter_unsupported_algo",0); else set_string("no_perimeter_unsupported_algo", "filled"); } + +// quick settings bed temp +int s_bed_temp_fff_get(string &out get_val) +{ + int bed_temperature = get_int("bed_temperature"); + int fl_bed_temperature = get_int("first_layer_bed_temperature"); + if (bed_temperature >= 70 && fl_bed_temperature >= 70) { + return 0; //hot + } + if (bed_temperature >= 45 && fl_bed_temperature >= 45) { + return 1; //mild + } + return 2; // cold +} +void s_bed_temp_fff_set(string &in new_val, int idx) +{ + if(idx == 0) { // hot + set_int("bed_temperature", 70); + set_int("first_layer_bed_temperature", 75); + } else if(idx == 1) { // mild + set_int("bed_temperature", 45); + set_int("first_layer_bed_temperature", 50); + } else if(idx == 2) { // cold + set_int("bed_temperature", 0); + set_int("first_layer_bed_temperature", 0); + } +} + + +// quick settings orientation +int s_orientation_fff_get(string &out get_val) +{ + float orientation = get_float("init_z_rotate"); + if (orientation == 0) { + return 0; // normal + } + if (orientation == 45) { + return 1; // 45° + } + return 3; // custom +} +void s_orientation_fff_set(string &in new_val, int idx) +{ + if(idx == 0) { // normal + set_float("init_z_rotate", 0); + } else if(idx == 1) { // 45° + set_float("init_z_rotate", 45); + } else if(idx == 2) { // reset + back_initial_value("init_z_rotate"); + } +} + diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index 0b13859e207..458635d5040 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -224,6 +224,13 @@ static inline Slic3r::ThickPolyline to_thick_polyline(const ClipperLib_Z::Path & out.points_width.emplace_back(it->z()); } } + // Don't create 1-element polyline. + if(out.points.size() <2) + return {}; + + assert(out.points.back().coincides_with_epsilon(Point{ path.back().x(), path.back().y() })); + out.points.back() = Point{ path.back().x(), path.back().y() }; + assert(out.points.front().x() == path.front().x()); assert(out.points.front().y() == path.front().y()); assert(out.points.back().x() == path.back().x()); diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 90b7fbe17dd..549d6034904 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -421,7 +421,7 @@ struct GlobalModelInfo { //Extract perimeter polygons of the given layer Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition configured_seam_preference, - std::vector &corresponding_regions_out) { + std::vector &corresponding_regions_out, PerimeterGeneratorType perimeter_type) { Polygons polygons; @@ -430,13 +430,22 @@ Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition confi std::vector* corresponding_regions_out; const LayerRegion* current_layer_region; SeamPosition configured_seam_preference; + PerimeterGeneratorType perimeter_type; public: bool also_overhangs = false; bool also_thin_walls = false; - PerimeterCopy(std::vector* regions_out, Polygons* polys, SeamPosition configured_seam) - : corresponding_regions_out(regions_out), configured_seam_preference(configured_seam), polygons(polys) { + PerimeterCopy(std::vector* regions_out, Polygons* polys, SeamPosition configured_seam, PerimeterGeneratorType perimeter_type) + : corresponding_regions_out(regions_out), configured_seam_preference(configured_seam), polygons(polys), perimeter_type(perimeter_type) { } virtual void default_use(const ExtrusionEntity& entity) {}; + virtual void use(const ExtrusionPath &path) override { + if (perimeter_type == PerimeterGeneratorType::Arachne && path.role() != erThinWall) { + path.polygons_covered_by_width(*polygons, SCALED_EPSILON); + while (corresponding_regions_out->size() < polygons->size()) { + corresponding_regions_out->push_back(current_layer_region); + } + } + } virtual void use(const ExtrusionLoop& loop) override { if ((configured_seam_preference == spAllRandom && !loop.paths.empty() && is_perimeter(loop.paths.front().role())) @@ -468,13 +477,27 @@ Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition confi } } } + virtual void use(const ExtrusionMultiPath& collection) override { + + if (perimeter_type == PerimeterGeneratorType::Arachne) { + Polygons polys; + for (const ExtrusionPath& path : collection.paths) { + path.polygons_covered_by_width(polys, SCALED_EPSILON); + } + polys = union_(polys); + append(*polygons, polys); + while (corresponding_regions_out->size() < polygons->size()) { + corresponding_regions_out->push_back(current_layer_region); + } + } + } virtual void use(const ExtrusionEntityCollection& collection) override { for (const ExtrusionEntity* entity : collection.entities()) { entity->visit(*this); } } void set_current_layer_region(const LayerRegion *set) { current_layer_region = set; } - } visitor(&corresponding_regions_out, &polygons, configured_seam_preference); + } visitor(&corresponding_regions_out, &polygons, configured_seam_preference, perimeter_type); for (const LayerRegion *layer_region : layer->regions()) { for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities()) { @@ -504,13 +527,12 @@ Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition confi } } } - if (polygons.empty()) { // If there are no perimeter polygons for whatever reason (disabled perimeters .. ) insert dummy point // it is easier than checking everywhere if the layer is not emtpy, no seam will be placed to this layer anyway polygons.emplace_back(std::vector { Point { 0, 0 } }); corresponding_regions_out.push_back(nullptr); } - + assert(corresponding_regions_out.size() == polygons.size()); return polygons; } @@ -1144,7 +1166,7 @@ void SeamPlacer::gather_seam_candidates(const PrintObject *po, auto unscaled_z = layer->slice_z; std::vector regions; //NOTE corresponding region ptr may be null, if the layer has zero perimeters - Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions); + Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions, po->config().perimeter_generator.value); for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) { process_perimeter_polygon(polygons[poly_index], unscaled_z, regions[poly_index], global_model_info, layer_seams); @@ -1622,6 +1644,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: void SeamPlacer::init(const Print &print, std::function throw_if_canceled_func) { using namespace SeamPlacerImpl; m_seam_per_object.clear(); + this->external_perimeters_first = print.default_region_config().external_perimeters_first; for (const PrintObject *po : print.objects()) { throw_if_canceled_func(); @@ -1690,7 +1713,6 @@ void SeamPlacer::init(const Print &print, std::function throw_if_can debug_export_points(m_seam_per_object[po].layers, po->bounding_box(), comparator); #endif } - this->external_perimeters_first = print.default_region_config().external_perimeters_first; } static constexpr float MINIMAL_POLYGON_SIDE = scaled(0.2f); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 68bdad07e45..94c39100a4f 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -2281,10 +2281,11 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar assert(thickpaths[i - 1].last_point() == thickpaths[i].first_point()); } #endif - assert(thickpaths.front().first_point().x() == arachne_path.front().x()); - assert(thickpaths.front().first_point().y() == arachne_path.front().y()); - assert(thickpaths.back().last_point().x() == arachne_path.back().x()); - assert(thickpaths.back().last_point().y() == arachne_path.back().y()); + // thickpaths can be empty if extrusion_path is too short + assert(thickpaths.empty() || thickpaths.front().first_point().x() == arachne_path.front().x()); + assert(thickpaths.empty() || thickpaths.front().first_point().y() == arachne_path.front().y()); + assert(thickpaths.empty() || thickpaths.back().last_point().x() == arachne_path.back().x()); + assert(thickpaths.empty() || thickpaths.back().last_point().y() == arachne_path.back().y()); for (ExtrusionPath& path : thickpaths) { path.set_can_reverse(!is_loop); paths.push_back(std::move(path)); @@ -2303,10 +2304,11 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar assert(thickpaths[i - 1].last_point() == thickpaths[i].first_point()); } #endif - assert(thickpaths.front().first_point().x() == extrusion_path.front().x()); - assert(thickpaths.front().first_point().y() == extrusion_path.front().y()); - assert(thickpaths.back().last_point().x() == extrusion_path.back().x()); - assert(thickpaths.back().last_point().y() == extrusion_path.back().y()); + // thickpaths can be empty if extrusion_path is too short + assert(thickpaths.empty() || thickpaths.front().first_point().x() == extrusion_path.front().x()); + assert(thickpaths.empty() || thickpaths.front().first_point().y() == extrusion_path.front().y()); + assert(thickpaths.empty() || thickpaths.back().last_point().x() == extrusion_path.back().x()); + assert(thickpaths.empty() || thickpaths.back().last_point().y() == extrusion_path.back().y()); for (ExtrusionPath& path : thickpaths) { path.set_can_reverse(!is_loop); path.height = 0; @@ -2326,10 +2328,11 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar assert(thickpaths[i - 1].last_point() == thickpaths[i].first_point()); } #endif - assert(thickpaths.front().first_point().x() == extrusion_path.front().x()); - assert(thickpaths.front().first_point().y() == extrusion_path.front().y()); - assert(thickpaths.back().last_point().x() == extrusion_path.back().x()); - assert(thickpaths.back().last_point().y() == extrusion_path.back().y()); + // thickpaths can be empty if extrusion_path is too short + assert(thickpaths.empty() || thickpaths.front().first_point().x() == extrusion_path.front().x()); + assert(thickpaths.empty() || thickpaths.front().first_point().y() == extrusion_path.front().y()); + assert(thickpaths.empty() || thickpaths.back().last_point().x() == extrusion_path.back().x()); + assert(thickpaths.empty() || thickpaths.back().last_point().y() == extrusion_path.back().y()); for (ExtrusionPath& path : thickpaths) { path.set_can_reverse(!is_loop); path.height = no_small_flow ? 2 : 1; @@ -2349,10 +2352,11 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar assert(thickpaths[i - 1].last_point() == thickpaths[i].first_point()); } #endif - assert(thickpaths.front().first_point().x() == extrusion_path.front().x()); - assert(thickpaths.front().first_point().y() == extrusion_path.front().y()); - assert(thickpaths.back().last_point().x() == extrusion_path.back().x()); - assert(thickpaths.back().last_point().y() == extrusion_path.back().y()); + // thickpaths can be empty if extrusion_path is too short + assert(thickpaths.empty() || thickpaths.front().first_point().x() == extrusion_path.front().x()); + assert(thickpaths.empty() || thickpaths.front().first_point().y() == extrusion_path.front().y()); + assert(thickpaths.empty() || thickpaths.back().last_point().x() == extrusion_path.back().x()); + assert(thickpaths.empty() || thickpaths.back().last_point().y() == extrusion_path.back().y()); for (ExtrusionPath& path : thickpaths) { path.set_can_reverse(!is_loop); path.height = no_small_flow ? 3 : 2; @@ -2372,10 +2376,11 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar assert(thickpaths[i - 1].last_point() == thickpaths[i].first_point()); } #endif - assert(thickpaths.front().first_point().x() == extrusion_path.front().x()); - assert(thickpaths.front().first_point().y() == extrusion_path.front().y()); - assert(thickpaths.back().last_point().x() == extrusion_path.back().x()); - assert(thickpaths.back().last_point().y() == extrusion_path.back().y()); + // thickpaths can be empty if extrusion_path is too short + assert(thickpaths.empty() || thickpaths.front().first_point().x() == extrusion_path.front().x()); + assert(thickpaths.empty() || thickpaths.front().first_point().y() == extrusion_path.front().y()); + assert(thickpaths.empty() || thickpaths.back().last_point().x() == extrusion_path.back().x()); + assert(thickpaths.empty() || thickpaths.back().last_point().y() == extrusion_path.back().y()); for (ExtrusionPath& path : thickpaths) { // change flow to overhang one if too much. if (path.mm3_per_mm > this->overhang_flow.mm3_per_mm() ){ @@ -2420,11 +2425,41 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar } //FIXME from here, it's exactly the same as the other create_overhangs, please merge that into a function. - + + //(or not) + Point first_point(arachne_path.front().x(), arachne_path.front().y()); // reapply the nearest point search for starting point // We allow polyline reversal because Clipper may have randomly reversed polylines during clipping. if (!paths.empty()) - chain_and_reorder_extrusion_paths(paths, &paths.front().first_point()); + chain_and_reorder_extrusion_paths(paths, &first_point); + + //check if evvrything is okay (it can fail) + bool not_sorted_enough = false; + for (int i = 1; i < paths.size(); i++) { + if (!paths[i - 1].last_point().coincides_with_epsilon(paths[i].first_point())) { + not_sorted_enough = true; + break; + } + } + if (not_sorted_enough) { + Point other_point = paths[1].first_point(); + chain_and_reorder_extrusion_paths(paths, &other_point); + auto path = paths.back(); + paths.erase(paths.end()-1); + paths.insert(paths.begin(), path); + bool not_sorted_enough = false; + for (int i = 1; i < paths.size(); i++) { + if (paths[i - 1].last_point().coincides_with_epsilon(paths[i].first_point())) { + not_sorted_enough = true; + break; + } + } + if (not_sorted_enough) { + // do it manually by brute-force + // TODO + chain_and_reorder_extrusion_paths(paths, &first_point); + } + } for (int i = 1; i < paths.size(); i++) { // diff/inter can generate points with ~3-5 unit of diff. diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 5f316ef6fee..2b3e1653b6e 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -242,6 +242,7 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, return it->second; wxImage image; + BOOST_LOG_TRIVIAL(error) << "Loading (forced png) image: '"<bool { if (wxFileExists(bitmap_file)) { + BOOST_LOG_TRIVIAL(error) << "Loading (png) image for wizard: '"<