diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 34d0c09583..7e09a6418b 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,5 +1,6 @@ -min_slic3r_version = 2.4.0-beta0 +min_slic3r_version = 2.4.0-beta2 1.4.0-beta2 Added SLA material colors. Updated BASF filament profiles. +min_slic3r_version = 2.4.0-beta0 1.4.0-beta1 Updated pad wall slope angle for SLA printers. Updated Filatech Filacarbon profile for Prusa MINI. 1.4.0-beta0 Added multiple Filatech and BASF filament profiles. Added material profiles for SL1S. min_slic3r_version = 2.4.0-alpha0 diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f9f116f8e2..f6105b180c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1544,30 +1544,37 @@ void GCode::process_layers( const size_t single_object_idx, GCodeOutputStream &output_stream) { - // The pipeline is fixed: Neither wipe tower nor vase mode are implemented for sequential print. + // The pipeline is variable: The vase mode filter is optional. size_t layer_to_print_idx = 0; - tbb::parallel_pipeline(12, - tbb::make_filter( - tbb::filter::serial_in_order, - [this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult { - if (layer_to_print_idx == layers_to_print.size()) { - fc.stop(); - return {}; - } else { - LayerToPrint &layer = layers_to_print[layer_to_print_idx ++]; - print.throw_if_canceled(); - return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx); - } - }) & - tbb::make_filter( - tbb::filter::serial_in_order, - [&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string { - return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); - }) & - tbb::make_filter( - tbb::filter::serial_in_order, - [&output_stream](std::string s) { output_stream.write(s); } - )); + const auto generator = tbb::make_filter(tbb::filter::serial_in_order, + [this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult { + if (layer_to_print_idx == layers_to_print.size()) { + fc.stop(); + return {}; + } else { + LayerToPrint &layer = layers_to_print[layer_to_print_idx ++]; + print.throw_if_canceled(); + return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx); + } + }); + const auto spiral_vase = tbb::make_filter(tbb::filter::serial_in_order, + [&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in)->GCode::LayerResult { + spiral_vase.enable(in.spiral_vase_enable); + return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush }; + }); + const auto cooling = tbb::make_filter(tbb::filter::serial_in_order, + [&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in)->std::string { + return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); + }); + const auto output = tbb::make_filter(tbb::filter::serial_in_order, + [&output_stream](std::string s) { output_stream.write(s); } + ); + + // The pipeline elements are joined using const references, thus no copying is performed. + if (m_spiral_vase) + tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output); + else + tbb::parallel_pipeline(12, generator & cooling & output); } std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 52de3a341a..f8f02e0fdb 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -613,13 +613,25 @@ const PrintObjectRegions::BoundingBox* find_volume_extents(const PrintObjectRegi } // Find a bounding box of a topmost printable volume referenced by this modifier given this_region_id. -const PrintObjectRegions::BoundingBox* find_modifier_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const int this_region_id) +PrintObjectRegions::BoundingBox find_modifier_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const int this_region_id) { // Find the top-most printable volume of this modifier, or the printable volume itself. - int parent_region_id = this_region_id; - for (; ! layer_range.volume_regions[parent_region_id].model_volume->is_model_part(); parent_region_id = layer_range.volume_regions[parent_region_id].parent) - assert(parent_region_id >= 0); - return find_volume_extents(layer_range, *layer_range.volume_regions[parent_region_id].model_volume); + const PrintObjectRegions::VolumeRegion &this_region = layer_range.volume_regions[this_region_id]; + const PrintObjectRegions::BoundingBox *this_extents = find_volume_extents(layer_range, *this_region.model_volume); + assert(this_extents); + PrintObjectRegions::BoundingBox out { *this_extents }; + if (! this_region.model_volume->is_model_part()) + for (int parent_region_id = this_region.parent;;) { + assert(parent_region_id >= 0); + const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id]; + const PrintObjectRegions::BoundingBox *parent_extents = find_volume_extents(layer_range, *parent_region.model_volume); + assert(parent_extents); + out.extend(*parent_extents); + if (parent_region.model_volume->is_model_part()) + break; + parent_region_id = parent_region.parent; + } + return out; } PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_or_parent_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders); @@ -679,17 +691,13 @@ bool verify_update_print_object_regions( layer_range.volume_regions[next_region_id].parent == parent_region_id) { // A parent region is already overridden. ++ next_region_id; - } else { + } else if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) // Such parent region does not exist. If it is needed, then we need to reslice. - const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); - assert(parent_bbox != nullptr); - if (parent_bbox->intersects(*bbox)) - // Only create new region for a modifier, which actually modifies config of it's parent. - if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders); - config != parent_region.region->config()) - // This modifier newly overrides a region, which it did not before. We need to reslice. - return false; - } + // Only create new region for a modifier, which actually modifies config of it's parent. + if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders); + config != parent_region.region->config()) + // This modifier newly overrides a region, which it did not before. We need to reslice. + return false; } } } @@ -911,10 +919,8 @@ static PrintObjectRegions* generate_print_object_regions( for (int parent_region_id = int(layer_range.volume_regions.size()) - 1; parent_region_id >= 0; -- parent_region_id) { const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id]; const ModelVolume &parent_volume = *parent_region.model_volume; - if (parent_volume.is_model_part() || parent_volume.is_modifier()) { - const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); - assert(parent_bbox != nullptr); - if (parent_bbox->intersects(*bbox)) + if (parent_volume.is_model_part() || parent_volume.is_modifier()) + if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) // Only create new region for a modifier, which actually modifies config of it's parent. if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders); config != parent_region.region->config()) { @@ -922,7 +928,6 @@ static PrintObjectRegions* generate_print_object_regions( layer_range.volume_regions.push_back({ &volume, parent_region_id, get_create_region(std::move(config)), bbox }); } else if (parent_model_part_id == -1 && parent_volume.is_model_part()) parent_model_part_id = parent_region_id; - } } if (! added && parent_model_part_id >= 0) // This modifier does not override any printable volume's configuration, however it may in the future. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c637804495..2e0e2ff18b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2688,7 +2688,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Concentric")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(smpRectilinear)); + def->set_default_value(new ConfigOptionEnum(smipRectilinear)); def = this->add("support_material_spacing", coFloat); def->label = L("Pattern spacing"); diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 38db180434..05936f1394 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1866,9 +1866,13 @@ std::vector slice_mesh_ex( //FIXME simplify if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour) keep_largest_contour_only(expolygons); - if (resolution != 0.) - for (ExPolygon &ex : expolygons) - ex.simplify(resolution); + if (resolution != 0.) { + ExPolygons simplified; + simplified.reserve(expolygons.size()); + for (const ExPolygon &ex : expolygons) + append(simplified, ex.simplify(resolution)); + expolygons = std::move(simplified); + } } }); // BOOST_LOG_TRIVIAL(debug) << "slice_mesh make_expolygons in parallel - end"; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 7e64abcde1..0b2af37b8e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -162,8 +162,8 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (config->opt_bool("support_material")) { // Ask only once. - if (!support_material_overhangs_queried) { - support_material_overhangs_queried = true; + if (!m_support_material_overhangs_queried) { + m_support_material_overhangs_queried = true; if (!config->opt_bool("overhangs")/* != 1*/) { wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters")); @@ -182,7 +182,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } } else { - support_material_overhangs_queried = false; + m_support_material_overhangs_queried = false; } if (config->option("fill_density")->value == 100) { diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index 0d6250b5af..0e6815753e 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -17,15 +17,12 @@ class ModelConfig; namespace GUI { -// This variable have to be static because of use its value from Preset configuration -// and from object/parts configuration from the Settings in sidebar -static bool support_material_overhangs_queried {false}; - class ConfigManipulation { bool is_msg_dlg_already_exist{ false }; bool m_is_initialized_support_material_overhangs_queried{ false }; + bool m_support_material_overhangs_queried{ false }; // function to loading of changed configuration std::function load_config = nullptr; @@ -66,7 +63,7 @@ public: void initialize_support_material_overhangs_queried(bool queried) { m_is_initialized_support_material_overhangs_queried = true; - support_material_overhangs_queried = queried; + m_support_material_overhangs_queried = queried; } }; diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 363dadf1e4..88735902b0 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include "Field.hpp" #include "format.hpp" @@ -1446,6 +1447,18 @@ wxString Control::get_tooltip(int tick/*=-1*/) std::string space = " "; tooltip = space; auto format_gcode = [space](std::string gcode) { + // when the tooltip is too long, it starts to flicker, see: https://github.com/prusa3d/PrusaSlicer/issues/7368 + // so we limit the number of lines shown + std::vector lines; + boost::split(lines, gcode, boost::is_any_of("\n"), boost::token_compress_off); + static const size_t MAX_LINES = 10; + if (lines.size() > MAX_LINES) { + gcode = lines.front() + '\n'; + for (size_t i = 1; i < MAX_LINES; ++i) { + gcode += lines[i] + '\n'; + } + gcode += "[" + into_u8(_L("continue")) + "]\n"; + } boost::replace_all(gcode, "\n", "\n" + space); return gcode; }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9624b45787..0611fb28d5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -95,6 +95,11 @@ RetinaHelper::~RetinaHelper() {} float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleFactor()); } #endif // __WXGTK3__ +// Fixed the collision between BuildVolume::Type::Convex and macro Convex defined inside /usr/include/X11/X.h that is included by WxWidgets 3.0. +#if defined(__linux__) && defined(Convex) +#undef Convex +#endif + Size::Size() : m_width(0) , m_height(0) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 2b38b104f7..016c0dec8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -109,7 +109,7 @@ void GLGizmoSimplify::add_simplify_suggestion_notification( if (big_ids.empty()) return; for (size_t object_id : big_ids) { - std::string t = GUI::format(_u8L( + std::string t = GUI::format(_L( "Processing model '%1%' with more than 1M triangles " "could be slow. It is highly recommend to reduce " "amount of triangles."), objects[object_id]->name); diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 2b1d03b69f..da6840ef8a 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -96,7 +96,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr } add_button(wxID_CANCEL); - if (auto* btn_ok = get_button(wxID_NO); btn_ok != NULL) { + if (auto* btn_ok = get_button(wxID_OK); btn_ok != NULL) { btn_ok->SetLabel(_L("Upload")); btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) { wxString path = txt_filename->GetValue(); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index fc7afbb349..63c26f7217 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -127,6 +127,7 @@ struct Http::priv Http::CompleteFn completefn; Http::ErrorFn errorfn; Http::ProgressFn progressfn; + Http::IPResolveFn ipresolvefn; priv(const std::string &url); ~priv(); @@ -390,6 +391,13 @@ void Http::priv::http_perform() if (errorfn) { errorfn(std::move(buffer), std::string(), http_status); } } else { if (completefn) { completefn(std::move(buffer), http_status); } + if (ipresolvefn) { + char* ct; + res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ct); + if ((CURLE_OK == res) && ct) { + ipresolvefn(ct); + } + } } } } @@ -554,6 +562,12 @@ Http& Http::on_progress(ProgressFn fn) return *this; } +Http& Http::on_ip_resolve(IPResolveFn fn) +{ + if (p) { p->ipresolvefn = std::move(fn); } + return *this; +} + Http::Ptr Http::perform() { auto self = std::make_shared(std::move(*this)); diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index 61d84c51e8..2f458582d2 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -41,6 +41,8 @@ public: // Writing true to the `cancel` reference cancels the request in progress. typedef std::function ProgressFn; + typedef std::function IPResolveFn; + Http(Http &&other); // Note: strings are expected to be UTF-8-encoded @@ -113,6 +115,9 @@ public: // See the `Progress` structure for description of the data passed. // Writing a true-ish value into the cancel reference parameter cancels the request. Http& on_progress(ProgressFn fn); + // Callback called after succesful HTTP request (after on_complete callback) + // Called if curl_easy_getinfo resolved just used IP address. + Http& on_ip_resolve(IPResolveFn fn); // Starts performing the request in a background thread Ptr perform(); diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index f9ae4af5a1..12db505b2a 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -76,6 +76,9 @@ bool OctoPrint::test(wxString &msg) const }) #ifdef WIN32 .ssl_revoke_best_effort(m_ssl_revoke_best_effort) + .on_ip_resolve([&](std::string address) { + msg = boost::nowide::widen(address); + }) #endif .perform_sync(); @@ -108,9 +111,25 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro return false; } + std::string url; bool res = true; - auto url = make_url("api/files/local"); + if (m_host.find("https://") == 0 || test_msg.empty()) + { + // If https is entered we assume signed ceritificate is being used + // IP resolving will not happen - it could resolve into address not being specified in cert + url = make_url("api/files/local"); + } else { + // Curl uses easy_getinfo to get ip address of last successful transaction. + // If it got the address use it instead of the stored in "host" variable. + // This new address returns in "test_msg" variable. + // Solves troubles of uploades failing with name address. + std::string resolved_addr = boost::nowide::narrow(test_msg); + // put ipv6 into [] brackets (there shouldn't be any http:// if its resolved addr) + if (resolved_addr.find(':') != std::string::npos && resolved_addr.at(0) != '[') + resolved_addr = "[" + resolved_addr + "]"; + url = make_url("api/files/local", resolved_addr); + } BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%") % name @@ -176,6 +195,21 @@ std::string OctoPrint::make_url(const std::string &path) const } } +std::string OctoPrint::make_url(const std::string& path, const std::string& addr) const +{ + std::string hst = addr.empty() ? m_host : addr; + if (hst.find("http://") == 0 || hst.find("https://") == 0) { + if (hst.back() == '/') { + return (boost::format("%1%%2%") % hst % path).str(); + } + else { + return (boost::format("%1%/%2%") % hst % path).str(); + } + } else { + return (boost::format("http://%1%/%2%") % hst % path).str(); + } +} + SL1Host::SL1Host(DynamicPrintConfig *config) : OctoPrint(config), m_authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 48035b7951..481b797313 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -44,6 +44,7 @@ private: virtual void set_auth(Http &http) const; std::string make_url(const std::string &path) const; + std::string make_url(const std::string& path, const std::string& addr) const; }; class SL1Host: public OctoPrint diff --git a/version.inc b/version.inc index 27900ee801..379c8971c9 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer") -set(SLIC3R_VERSION "2.4.0-beta1") +set(SLIC3R_VERSION "2.4.0-beta2") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_RC_VERSION "2,4,0,0") set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")