diff --git a/deps/deps-linux.cmake b/deps/deps-linux.cmake index ae972327f..420638d2f 100644 --- a/deps/deps-linux.cmake +++ b/deps/deps-linux.cmake @@ -80,7 +80,6 @@ ExternalProject_Add(dep_libcurl --disable-smb --disable-smtp --disable-gopher - --disable-crypto-auth --without-gssapi --without-libpsl --without-libidn2 diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index a71a0ebfc..f985cc561 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -67,7 +67,6 @@ ExternalProject_Add(dep_libcurl --disable-smb --disable-smtp --disable-gopher - --disable-crypto-auth --without-gssapi --without-libpsl --without-libidn2 diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 370b2f85a..cd2c1178b 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -910,12 +910,16 @@ void mark_boundary_segments_touching_infill( const std::vector &contour_parameters = boundary_parameters[it_contour_and_segment->first]; const float contour_length = contour_parameters.back(); const float param_seg_pt1 = contour_parameters[it_contour_and_segment->second]; + const float param_seg_pt2 = contour_parameters[it_contour_and_segment->second + 1]; #ifdef INFILL_DEBUG_OUTPUT this->perimeter_overlaps.push_back({ Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.first).cast()), Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.second).cast()) }); #endif // INFILL_DEBUG_OUTPUT - const float param_overlap1 = param_seg_pt1 + interval.first; - const float param_overlap2 = param_seg_pt1 + interval.second; + assert(interval.first >= 0.); + assert(interval.second >= 0.); + assert(interval.first <= interval.second); + const auto param_overlap1 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.first)); + const auto param_overlap2 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.second)); // 2) Find the ContourIntersectionPoints before param_overlap1 and after param_overlap2. // Find the span of ContourIntersectionPoints, that is trimmed by the interval (param_overlap1, param_overlap2). ContourIntersectionPoint *ip_low, *ip_high; diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 5cbfed57c..5797c47a5 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -182,12 +182,14 @@ void FillGyroid::_fill_surface_single( polylines = intersection_pl(polylines, to_polygons(expolygon)); - if (! polylines.empty()) - // remove too small bits (larger than longer) + if (! polylines.empty()) { + // Remove very small bits, but be careful to not remove infill lines connecting thin walls! + // The infill perimeter lines should be separated by around a single infill line width. + const double minlength = scale_(0.8 * this->spacing); polylines.erase( - //FIXME what is the small size? Removing tiny extrusions disconnects walls! - std::remove_if(polylines.begin(), polylines.end(), [this](const Polyline &pl) { return pl.length() < scale_(this->spacing * 3); }), + std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) { return pl.length() < minlength; }), polylines.end()); + } if (! polylines.empty()) { // connect lines diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 0a75b6729..e3860af46 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -19,6 +19,7 @@ #include "FillRectilinear.hpp" // #define SLIC3R_DEBUG +// #define INFILL_DEBUG_OUTPUT // Make assert active if SLIC3R_DEBUG #ifdef SLIC3R_DEBUG @@ -26,6 +27,10 @@ #include "SVG.hpp" #endif +#if defined(SLIC3R_DEBUG) || defined(INFILL_DEBUG_OUTPUT) + #include "SVG.hpp" +#endif + #include // We want our version of assert. @@ -1870,6 +1875,60 @@ static std::vector generate_montonous_regions(std::vector &segs, + const std::vector &monotonic_regions, + const std::string &path) +{ + BoundingBox bbox = get_extents(poly_with_offset.polygons_src); + bbox.offset(scale_(3.)); + + ::Slic3r::SVG svg(path, bbox); + svg.draw(poly_with_offset.polygons_src); + svg.draw_outline(poly_with_offset.polygons_src, "green"); + svg.draw_outline(poly_with_offset.polygons_outer, "green"); + svg.draw_outline(poly_with_offset.polygons_inner, "green"); + + // Draw the infill line candidates in red. + for (const SegmentedIntersectionLine &sil : segs) { + for (size_t i = 0; i + 1 < sil.intersections.size(); ++ i) + if (sil.intersections[i].type == SegmentIntersection::INNER_LOW && sil.intersections[i + 1].type == SegmentIntersection::INNER_HIGH) { + Line l(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[i + 1].pos())); + svg.draw(l, "blue"); + } else if (sil.intersections[i].type == SegmentIntersection::INNER_HIGH && sil.intersections[i].has_vertical_up()) { + std::string color; + const SegmentIntersection *it = &sil.intersections[i]; + switch (it->vertical_up_quality()) { + case SegmentIntersection::LinkQuality::Invalid: color = "red"; break; + case SegmentIntersection::LinkQuality::Valid: color = "blue"; break; + case SegmentIntersection::LinkQuality::TooLong: + default: color = "yellow"; break; + } + Polyline polyline; + polyline.points.push_back({ sil.pos, it->pos() }); + emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, &sil - segs.data() , it->iContour, it - sil.intersections.data(), it->vertical_up(), polyline, it->has_left_vertical_up()); + svg.draw(polyline, color, scale_(0.05)); + } + } + + // Draw the monotonic regions. + for (const MonotonicRegion ®ion : monotonic_regions) { + auto draw_boundary_line = [&poly_with_offset, &segs, &svg](const MonotonicRegion::Boundary &boundary) { + const SegmentedIntersectionLine &sil = segs[boundary.vline]; + for (size_t i = boundary.low; i < boundary.high; ++ i) + if (sil.intersections[i].type == SegmentIntersection::INNER_LOW && sil.intersections[i + 1].type == SegmentIntersection::INNER_HIGH) { + Line l(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[i + 1].pos())); + svg.draw(l, "red", scale_(0.05)); + } + }; + draw_boundary_line(region.left); + draw_boundary_line(region.right); + } +} +#endif // INFILL_DEBUG_OUTPUT + // Traverse path, calculate length of the draw for the purpose of optimization. // This function is very similar to polylines_from_paths() in the way how it traverses the path, but // polylines_from_paths() emits a path, while this function just calculates the path length. @@ -1928,14 +1987,22 @@ static float montonous_region_path_length(const MonotonicRegion ®ion, bool di break; int inext = it->right_horizontal(); - if (inext != -1 && it->next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) { + assert(iright != -1); + assert(inext == -1 || inext == iright); + + // Find the end of the next overlapping vertical segment. + const SegmentedIntersectionLine &vline_right = segs[i_vline + 1]; + const SegmentIntersection *right = going_up ? + &vertical_run_top(vline_right, vline_right.intersections[iright]) : &vertical_run_bottom(vline_right, vline_right.intersections[iright]); + i_intersection = int(right - vline_right.intersections.data()); + + if (inext == i_intersection && it->next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) { // Summarize length of the connection line along the perimeter. //FIXME should it be weighted with a lower weight than non-extruding connection line? What weight? // Taking half of the length. total_length += 0.5f * float(measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline, it - vline.intersections.data(), inext)); // Don't add distance to the next vertical line start to the total length. - no_perimeter = false; - i_intersection = inext; + no_perimeter = false; } else { // Finish the current vertical line, going_up ? ++ it : -- it; @@ -1945,14 +2012,6 @@ static float montonous_region_path_length(const MonotonicRegion ®ion, bool di last_point = Vec2f(vline.pos, it->pos()); // Remember to add distance to the last point. no_perimeter = true; - if (inext == -1) { - // Find the end of the next overlapping vertical segment. - const SegmentedIntersectionLine &vline_right = segs[i_vline + 1]; - const SegmentIntersection *right = going_up ? - &vertical_run_top(vline_right, vline_right.intersections[iright]) : &vertical_run_bottom(vline_right, vline_right.intersections[iright]); - i_intersection = int(right - vline_right.intersections.data()); - } else - i_intersection = inext; } ++ i_vline; @@ -2493,7 +2552,7 @@ static void polylines_from_paths(const std::vector &path, c for (const MonotonicRegionLink &path_segment : path) { MonotonicRegion ®ion = *path_segment.region; - bool dir = path_segment.flipped; + bool dir = path_segment.flipped; // From the initial point (i_vline, i_intersection), follow a path. int i_intersection = region.left_intersection_point(dir); @@ -2579,11 +2638,19 @@ static void polylines_from_paths(const std::vector &path, c if (i_vline == region.right.vline) break; - int inext = it->right_horizontal(); - if (inext != -1 && it->next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) { + int inext = it->right_horizontal(); + assert(iright != -1); + assert(inext == -1 || inext == iright); + + // Find the end of the next overlapping vertical segment. + const SegmentedIntersectionLine &vline_right = segs[i_vline + 1]; + const SegmentIntersection *right = going_up ? + &vertical_run_top(vline_right, vline_right.intersections[iright]) : &vertical_run_bottom(vline_right, vline_right.intersections[iright]); + i_intersection = int(right - vline_right.intersections.data()); + + if (inext == i_intersection && it->next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) { // Emit a horizontal connection contour. emit_perimeter_prev_next_segment(poly_with_offset, segs, i_vline, it->iContour, it - vline.intersections.data(), inext, *polyline, true); - i_intersection = inext; } else { // Finish the current vertical line, going_up ? ++ it : -- it; @@ -2591,14 +2658,6 @@ static void polylines_from_paths(const std::vector &path, c assert(it->is_high() == going_up); polyline->points.back() = Point(vline.pos, it->pos()); finish_polyline(); - if (inext == -1) { - // Find the end of the next overlapping vertical segment. - const SegmentedIntersectionLine &vline_right = segs[i_vline + 1]; - const SegmentIntersection *right = going_up ? - &vertical_run_top(vline_right, vline_right.intersections[iright]) : &vertical_run_bottom(vline_right, vline_right.intersections[iright]); - i_intersection = int(right - vline_right.intersections.data()); - } else - i_intersection = inext; } ++ i_vline; @@ -2717,6 +2776,12 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa // Insert phony OUTER_HIGH / OUTER_LOW pairs at the position where the contour is pinched. pinch_contours_insert_phony_outer_intersections(segs); std::vector regions = generate_montonous_regions(segs); +#ifdef INFILL_DEBUG_OUTPUT + { + static int iRun; + export_monotonous_regions_to_svg(poly_with_offset, segs, regions, debug_out_path("%s-%03d.svg", "MontonousRegions-initial", iRun ++)); + } +#endif // INFILL_DEBUG_OUTPUT connect_monotonic_regions(regions, poly_with_offset, segs); if (! regions.empty()) { std::mt19937_64 rng; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index a0176ad4a..7c7838afa 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -861,9 +861,15 @@ void Choice::BUILD() { temp->SetItemBitmap(0, empty_bmp); #endif -// temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); temp->Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_is_dropped = true; }); - temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_is_dropped = false; }); + temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this, temp](wxCommandEvent&) { + // EVT_COMBOBOX_CLOSEUP is called after EVT_COMBOBOX on Windows + // so, always set m_suppress_change to "true" +#ifndef __WXMSW__ + if (m_last_selected == temp->GetSelection()) +#endif //__WXMSW__ + m_is_dropped = false; + }); temp->Bind(wxEVT_COMBOBOX, ([this, temp](wxCommandEvent evt) { if (m_suppress_scroll) { @@ -874,6 +880,7 @@ void Choice::BUILD() { m_last_selected = evt.GetSelection(); } on_change_field(); + m_is_dropped = false; }), temp->GetId()); if (m_is_editable) { @@ -998,13 +1005,14 @@ void Choice::set_value(const boost::any& value, bool change_event) else text_value = boost::any_cast(value); size_t idx = 0; - for (auto el : m_opt.enum_values) + const std::vector& enums = m_opt.enum_values.empty() ? m_opt.enum_labels : m_opt.enum_values; + for (auto el : enums) { if (el == text_value) break; ++idx; } - if (idx == m_opt.enum_values.size()) { + if (idx == enums.size()) { // For editable Combobox under OSX is needed to set selection to -1 explicitly, // otherwise selection doesn't be changed field->SetSelection(-1); @@ -1012,7 +1020,7 @@ void Choice::set_value(const boost::any& value, bool change_event) } else field->SetSelection(idx); - if (m_suppress_scroll && idx < m_opt.enum_values.size()) m_last_selected = idx; + if (m_suppress_scroll && idx < enums.size()) m_last_selected = idx; break; } case coEnum: { diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index b9096ce10..a82161055 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -189,10 +189,10 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_ } else { + m_printer = *printer; const std::set& preset_names = printer->get_preset_names(); for (const std::string& preset_name : preset_names) m_presets.emplace_back(new PresetForPrinter(this, preset_name)); - m_printer = *printer; } if (m_presets.size() == 1) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 11c2448b7..05a30584a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -513,6 +513,10 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : m_og_sla->append_line(line); m_og_sla->activate(); + choice = dynamic_cast(m_og_sla->get_field("support")); + choice->suppress_scroll(); + choice = dynamic_cast(m_og_sla->get_field("pad")); + choice->suppress_scroll(); m_sizer = new wxBoxSizer(wxVERTICAL); m_sizer->Add(m_og->sizer, 0, wxEXPAND); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 78559b937..1fbded377 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -103,8 +103,15 @@ PresetComboBox::PresetComboBox(wxWindow* parent, Preset::Type preset_type, const // parameters for an icon's drawing fill_width_height(); - Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent& evt) { m_suppress_change = false; }); - Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent& evt) { m_suppress_change = true ; }); + Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_suppress_change = false; }); + Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { + // EVT_COMBOBOX_CLOSEUP is called after EVT_COMBOBOX on Windows + // so, always set m_suppress_change to "true" +#ifndef __WXMSW__ + if (m_last_selected == this->GetSelection()) +#endif //__WXMSW__ + m_suppress_change = true; + }); Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) { // see https://github.com/prusa3d/PrusaSlicer/issues/3889 @@ -572,6 +579,7 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset } else { evt.StopPropagation(); } + m_suppress_change = true; }); if (m_type == Preset::TYPE_FILAMENT) @@ -911,6 +919,7 @@ TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type) } evt.StopPropagation(); + m_suppress_change = true; }); } diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 31b23defd..94a8c9a56 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -448,6 +448,15 @@ Http& Http::auth_digest(const std::string &user, const std::string &password) return *this; } +Http& Http::auth_basic(const std::string &user, const std::string &password) +{ + curl_easy_setopt(p->curl, CURLOPT_USERNAME, user.c_str()); + curl_easy_setopt(p->curl, CURLOPT_PASSWORD, password.c_str()); + curl_easy_setopt(p->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + + return *this; +} + Http& Http::ca_file(const std::string &name) { if (p && priv::ca_file_supported(p->curl)) { diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index b629fb328..f34a27fbc 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -67,6 +67,8 @@ public: Http& remove_header(std::string name); // Authorization by HTTP digest, based on RFC2617. Http& auth_digest(const std::string &user, const std::string &password); + // Basic HTTP authorization + Http& auth_basic(const std::string &user, const std::string &password); // Sets a CA certificate file for usage with HTTPS. This is only supported on some backends, // specifically, this is supported with OpenSSL and NOT supported with Windows and OS X native certificate store. // See also ca_file_supported(). diff --git a/tests/slic3rutils/slic3rutils_tests_main.cpp b/tests/slic3rutils/slic3rutils_tests_main.cpp index b82114976..06989c5ee 100644 --- a/tests/slic3rutils/slic3rutils_tests_main.cpp +++ b/tests/slic3rutils/slic3rutils_tests_main.cpp @@ -2,7 +2,7 @@ #include "slic3r/Utils/Http.hpp" -TEST_CASE("Http", "[Http][NotWorking]") { +TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") { Slic3r::Http g = Slic3r::Http::get("https://github.com/"); @@ -20,3 +20,41 @@ TEST_CASE("Http", "[Http][NotWorking]") { REQUIRE(status == 200); } +TEST_CASE("Http digest authentication", "[Http][NotWorking]") { + Slic3r::Http g = Slic3r::Http::get("https://jigsaw.w3.org/HTTP/Digest/"); + + g.auth_digest("guest", "guest"); + + unsigned status = 0; + g.on_error([&status](std::string, std::string, unsigned http_status) { + status = http_status; + }); + + g.on_complete([&status](std::string /* body */, unsigned http_status){ + status = http_status; + }); + + g.perform_sync(); + + REQUIRE(status == 200); +} + +TEST_CASE("Http basic authentication", "[Http][NotWorking]") { + Slic3r::Http g = Slic3r::Http::get("https://jigsaw.w3.org/HTTP/Basic/"); + + g.auth_basic("guest", "guest"); + + unsigned status = 0; + g.on_error([&status](std::string, std::string, unsigned http_status) { + status = http_status; + }); + + g.on_complete([&status](std::string /* body */, unsigned http_status){ + status = http_status; + }); + + g.perform_sync(); + + REQUIRE(status == 200); +} +