diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ffffd9d319..07031d7e46 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2308,7 +2308,8 @@ void GCode::process_layer_single_object( ExtrusionEntitiesPtr temp_fill_extrusions; if (const Layer *layer = layer_to_print.object_layer; layer) - for (const LayerSlice &lslice : layer->lslices_ex) { + for (size_t idx : layer->lslice_indices_sorted_by_print_order) { + const LayerSlice &lslice = layer->lslices_ex[idx]; auto extrude_infill_range = [&]( const LayerRegion &layerm, const ExtrusionEntityCollection &fills, LayerExtrusionRanges::const_iterator it_fill_ranges_begin, LayerExtrusionRanges::const_iterator it_fill_ranges_end, bool ironing) { diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 441825654c..f7f6bb2f99 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -728,7 +728,7 @@ void Transformation::reset_skew() const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2)); - scale(0, 0) = average_scale; + scale(0, 0) = is_left_handed() ? -average_scale : average_scale; scale(1, 1) = average_scale; scale(2, 2) = average_scale; diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 0421c08068..aa37d94dd2 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -470,7 +470,7 @@ public: Transform3d get_mirror_matrix() const; bool is_left_handed() const { - return m_matrix.affine().determinant() < 0; + return m_matrix.linear().determinant() < 0; } #else bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 9b0004e989..378352be7d 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -38,32 +38,37 @@ LayerRegion* Layer::add_region(const PrintRegion *print_region) // merge all regions' slices to get islands void Layer::make_slices() { - ExPolygons slices; - if (m_regions.size() == 1) { - // optimization: if we only have one region, take its slices - slices = to_expolygons(m_regions.front()->slices().surfaces); - } else { - Polygons slices_p; - for (LayerRegion *layerm : m_regions) - polygons_append(slices_p, to_polygons(layerm->slices().surfaces)); - slices = union_safety_offset_ex(slices_p); + { + ExPolygons slices; + if (m_regions.size() == 1) { + // optimization: if we only have one region, take its slices + slices = to_expolygons(m_regions.front()->slices().surfaces); + } else { + Polygons slices_p; + for (LayerRegion *layerm : m_regions) + polygons_append(slices_p, to_polygons(layerm->slices().surfaces)); + slices = union_safety_offset_ex(slices_p); + } + // lslices are sorted by topological order from outside to inside from the clipper union used above + this->lslices = slices; } - - this->lslices.clear(); - this->lslices.reserve(slices.size()); - + + // prepare lslices ordered by print order + this->lslice_indices_sorted_by_print_order.clear(); + this->lslice_indices_sorted_by_print_order.reserve(lslices.size()); // prepare ordering points Points ordering_points; - ordering_points.reserve(slices.size()); - for (const ExPolygon &ex : slices) + ordering_points.reserve( this->lslices.size()); + for (const ExPolygon &ex : this->lslices) ordering_points.push_back(ex.contour.first_point()); // sort slices std::vector order = chain_points(ordering_points); - + // populate slices vector - for (size_t i : order) - this->lslices.emplace_back(std::move(slices[i])); + for (size_t i : order) { + this->lslice_indices_sorted_by_print_order.emplace_back(i); + } } // used by Layer::build_up_down_graph() diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index cfeace67be..11193828cc 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -336,6 +336,7 @@ public: // These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important // that the 1st lslice is not compensated by the Elephant foot compensation algorithm. ExPolygons lslices; + std::vector lslice_indices_sorted_by_print_order; LayerSlices lslices_ex; size_t region_count() const { return m_regions.size(); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index d6a4692f3f..76f784d6da 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -444,7 +444,7 @@ static std::vector s_Preset_print_options { "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", - "min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", + "min_skirt_length", "brim_width", "brim_separation", "brim_type", "check_for_issues_mode", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1d0446ce27..8c0b0f928d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -537,7 +537,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(60)); def = this->add("enable_dynamic_overhang_speeds", coBool); - def->label = L("Enable dynamic overhang speeds (Experimental)"); + def->label = L("Enable dynamic overhang speeds"); def->category = L("Speed"); def->tooltip = L("This setting enables dynamic speed control on overhangs."); def->mode = comAdvanced; @@ -2589,6 +2589,14 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(SlicingMode::Regular)); + def = this->add("check_for_issues_mode", coBool); + def->label = L("Check for issues: "); + def->category = L("Support material"); + def->tooltip = L("Check for supportable issues that may appear during printing. " + "If enabled, slicer will make alerts when it detects " + "issues that may be resolved with supports and/or brim."); + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("support_material", coBool); def->label = L("Generate support material"); def->category = L("Support material"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6bfc7723da..bdf82e3be0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -516,6 +516,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, wall_distribution_count)) ((ConfigOptionFloatOrPercent, min_feature_size)) ((ConfigOptionFloatOrPercent, min_bead_width)) + ((ConfigOptionBool, check_for_issues_mode)) ((ConfigOptionBool, support_material)) // Automatic supports (generated based fdm support point generator). ((ConfigOptionBool, support_material_auto)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 82b69baa38..8fc0169507 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -462,7 +462,7 @@ void PrintObject::generate_support_spots() } }; - if (!this->has_support()) { + if (!this->has_support() && this->config().check_for_issues_mode.getBool()) { SupportSpotsGenerator::raise_alerts_for_issues(supp_points, partial_objects, alert_fn); } } @@ -619,6 +619,8 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posSupportSpotsSearch); // Brim is printed below supports, support invalidates brim and skirt. steps.emplace_back(posSupportMaterial); + }else if (opt_key == "check_for_issues_mode") { + steps.emplace_back(posSupportSpotsSearch); } else if ( opt_key == "perimeters" || opt_key == "extra_perimeters" diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 81e21f305d..0d950b93ed 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -799,7 +799,7 @@ void PrintObject::slice_volumes() layer->m_regions[region_id]->trim_surfaces(trimming); } } - // Merge all regions' slices to get islands, chain them by a shortest path. + // Merge all regions' slices to get islands sorted topologically, chain them by a shortest path in separate index list layer->make_slices(); } }); diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 3820aa4d5e..47e7228d4d 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -260,8 +260,8 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit SupportPointCause potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor : SupportPointCause::LongBridge; - float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f; - Vec2d line_dir = (curr_point.position - prev_point.position).normalized(); + float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f; + Vec2d line_dir = line_len > EPSILON ? Vec2d((curr_point.position - prev_point.position) / double(line_len)) : Vec2d::Zero(); ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast() : curr_point.position.cast(), curr_point.position.cast(), line_len, entity}; @@ -335,14 +335,6 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit line_out.form_quality = 0.8f; bridged_distance += line_len; if (bridged_distance > max_bridge_len) { - std::cout << "Problem found A: " << std::endl; - std::cout << "bridged_distance: " << bridged_distance << std::endl; - std::cout << "max_bridge_len: " << max_bridge_len << std::endl; - std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl; - std::cout << "curr_point.distance: " << curr_point.distance << std::endl; - std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl; - std::cout << "flow_width: " << flow_width << std::endl; - line_out.support_point_generated = potential_cause; bridged_distance = 0.0f; } @@ -350,14 +342,6 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit bridged_distance += line_len; line_out.form_quality = nearest_prev_layer_line.form_quality - 0.3f; if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) { - std::cout << "Problem found B: " << std::endl; - std::cout << "bridged_distance: " << bridged_distance << std::endl; - std::cout << "max_bridge_len: " << max_bridge_len << std::endl; - std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl; - std::cout << "curr_point.distance: " << curr_point.distance << std::endl; - std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl; - std::cout << "flow_width: " << flow_width << std::endl; - line_out.support_point_generated = potential_cause; line_out.form_quality = 0.5f; bridged_distance = 0.0f; @@ -662,7 +646,8 @@ std::tuple build_object_part_from_slice(const size_t &slice_i } // BRIM HANDLING - if (layer->id() == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim) { + if (layer->id() == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim && + params.brim_width > 0.0) { // TODO: The algorithm here should take into account that multiple slices may have coliding Brim areas and the final brim area is // smaller, // thus has lower adhesion. For now this effect will be neglected. @@ -921,7 +906,8 @@ std::tuple check_stability(const PrintObject *po, for (const auto &perimeter_idx : island.perimeters) { const ExtrusionEntity *entity = perimeter_region->perimeters().entities[perimeter_idx]; std::vector perims = check_extrusion_entity_stability(entity, perimeter_region, - prev_layer_ext_perim_lines,prev_layer_boundary, params); + prev_layer_ext_perim_lines, prev_layer_boundary, + params); for (const ExtrusionLine &perim : perims) { if (perim.support_point_generated.has_value()) { reckon_new_support_point(*perim.support_point_generated, create_support_point_position(perim.b), -EPSILON, @@ -932,6 +918,30 @@ std::tuple check_stability(const PrintObject *po, } } } + // DEBUG EXPORT, NOT USED NOW + // if (BR_bridge) { + // Lines scaledl; + // for (const auto &l : prev_layer_boundary.get_lines()) { + // scaledl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b)); + // } + + // Lines perimsl; + // for (const auto &l : current_slice_ext_perims_lines) { + // perimsl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b)); + // } + + // BoundingBox bb = get_extents(scaledl); + // bb.merge(get_extents(perimsl)); + + // ::Slic3r::SVG svg(debug_out_path( + // ("slice" + std::to_string(slice_idx) + "_" + std::to_string(layer_idx).c_str()).c_str()), + // get_extents(scaledl)); + // svg.draw(scaledl, "red", scale_(0.4)); + // svg.draw(perimsl, "blue", scale_(0.25)); + + + // svg.Close(); + // } } LD current_slice_lines_distancer(current_slice_ext_perims_lines); @@ -1165,13 +1175,6 @@ void raise_alerts_for_issues(const SupportPoints PartialObjects &partial_objects, std::function alert_fn) { - for (const SupportPoint &sp : support_points) { - if (sp.cause == SupportPointCause::SeparationFromBed) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::SeparationFromBed); - break; - } - } - std::reverse(partial_objects.begin(), partial_objects.end()); std::sort(partial_objects.begin(), partial_objects.end(), [](const PartialObject &left, const PartialObject &right) { return left.volume > right.volume; }); @@ -1221,21 +1224,29 @@ void raise_alerts_for_issues(const SupportPoints } } - if (ext_supp_points.size() > 5) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::FloatingExtrusion); - } - for (const SupportPoint &sp : support_points) { - if (sp.cause == SupportPointCause::LongBridge) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::LongBridge); - break; + if (sp.cause == SupportPointCause::SeparationFromBed) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::SeparationFromBed); + return; } } for (const SupportPoint &sp : support_points) { if (sp.cause == SupportPointCause::WeakObjectPart) { alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::WeakObjectPart); - break; + return; + } + } + + if (ext_supp_points.size() > 5) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::FloatingExtrusion); + return; + } + + for (const SupportPoint &sp : support_points) { + if (sp.cause == SupportPointCause::LongBridge) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::LongBridge); + return; } } } diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 9b373312f0..8b34c9f44f 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -21,8 +21,6 @@ #include "MutablePolygon.hpp" #include "SupportMaterial.hpp" #include "TriangleMeshSlicer.hpp" -#include "OpenVDBUtilsLegacy.hpp" -#include #include #include @@ -45,6 +43,14 @@ #define TREE_SUPPORT_SHOW_ERRORS_WIN32 #endif +// #define TREE_SUPPORT_ORGANIC_NUDGE_NEW 1 + +#ifndef TREE_SUPPORT_ORGANIC_NUDGE_NEW + // Old version using OpenVDB, works but it is extremely slow for complex meshes. + #include "OpenVDBUtilsLegacy.hpp" + #include +#endif // TREE_SUPPORT_ORGANIC_NUDGE_NEW + namespace Slic3r { @@ -3389,8 +3395,6 @@ static void extrude_branch( } #endif -// #define TREE_SUPPORT_ORGANIC_NUDGE_NEW 1 - #ifdef TREE_SUPPORT_ORGANIC_NUDGE_NEW // New version using per layer AABB trees of lines for nudging spheres away from an object. static void organic_smooth_branches_avoid_collisions( diff --git a/src/slic3r/GUI/Downloader.cpp b/src/slic3r/GUI/Downloader.cpp index ad46162cbf..45ea436313 100644 --- a/src/slic3r/GUI/Downloader.cpp +++ b/src/slic3r/GUI/Downloader.cpp @@ -146,8 +146,7 @@ void Downloader::start_download(const std::string& full_url) #else std::string escaped_url = FileGet::escape_url(full_url.substr(24)); #endif - - if (!boost::starts_with(escaped_url, "https://files.printables.com") && !boost::starts_with(escaped_url, "https://dev-files.printables.com")) { + if (!boost::starts_with(escaped_url, "https://") || !FileGet::is_subdomain(escaped_url, "printables.com")) { std::string msg = format(_L("Download won't start. Download URL doesn't point to https://files.printables.com : %1%"), escaped_url); BOOST_LOG_TRIVIAL(error) << msg; NotificationManager* ntf_mngr = wxGetApp().notification_manager(); diff --git a/src/slic3r/GUI/DownloaderFileGet.cpp b/src/slic3r/GUI/DownloaderFileGet.cpp index d812612960..9eda212939 100644 --- a/src/slic3r/GUI/DownloaderFileGet.cpp +++ b/src/slic3r/GUI/DownloaderFileGet.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "format.hpp" @@ -30,6 +31,42 @@ std::string FileGet::escape_url(const std::string& unescaped) } return ret_val; } +bool FileGet::is_subdomain(const std::string& url, const std::string& domain) +{ + // domain should be f.e. printables.com (.com including) + char* host; + std::string host_string; + CURLUcode rc; + CURLU* curl = curl_url(); + if (!curl) { + BOOST_LOG_TRIVIAL(error) << "Failed to init Curl library in function is_domain."; + return false; + } + rc = curl_url_set(curl, CURLUPART_URL, url.c_str(), 0); + if (rc != CURLUE_OK) { + curl_url_cleanup(curl); + return false; + } + rc = curl_url_get(curl, CURLUPART_HOST, &host, 0); + if (rc != CURLUE_OK || !host) { + curl_url_cleanup(curl); + return false; + } + host_string = std::string(host); + curl_free(host); + // now host should be subdomain.domain or just domain + if (domain == host_string) { + curl_url_cleanup(curl); + return true; + } + if(boost::ends_with(host_string, "." + domain)) { + curl_url_cleanup(curl); + return true; + } + curl_url_cleanup(curl); + return false; +} + namespace { unsigned get_current_pid() { diff --git a/src/slic3r/GUI/DownloaderFileGet.hpp b/src/slic3r/GUI/DownloaderFileGet.hpp index 38ddd9af02..022d4c0c10 100644 --- a/src/slic3r/GUI/DownloaderFileGet.hpp +++ b/src/slic3r/GUI/DownloaderFileGet.hpp @@ -23,7 +23,8 @@ public: void cancel(); void pause(); void resume(); - static std::string escape_url(const std::string& url); + static std::string escape_url(const std::string& url); + static bool is_subdomain(const std::string& url, const std::string& domain); private: std::unique_ptr p; }; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e75f8836d2..c1490342ca 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3401,12 +3401,7 @@ void GUI_App::app_updater(bool from_user) if (dialog_result != wxID_OK) { return; } - if (dwnld_dlg.get_download_path().parent_path().empty() || !boost::filesystem::exists(dwnld_dlg.get_download_path().parent_path())) { - show_error(nullptr,GUI::format_wxstr(_L("Download can't proceed. Target directory doesn't exists: %1%"), dwnld_dlg.get_download_path().parent_path().string())); - return; - } app_data.target_path =dwnld_dlg.get_download_path(); - // start download this->plater_->get_notification_manager()->push_download_progress_notification(_utf8("Download"), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get())); app_data.start_after = dwnld_dlg.run_after_download(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index c069475659..cbe1805ee5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -53,7 +53,7 @@ static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = { { L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } }, { L("Infill") , { "fill_density", "fill_pattern" } }, - { L("Support material") , { "support_material", "support_material_auto", "support_material_threshold", + { L("Support material") , { "check_for_issues_mode", "support_material", "support_material_auto", "support_material_threshold", "support_material_pattern", "support_material_interface_pattern", "support_material_buildplate_only", "support_material_spacing" } }, { L("Wipe options") , { "wipe_into_infill", "wipe_into_objects" } } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index d737a7be47..103198ca8d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -235,7 +235,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : add_label(&m_scale_Label, L("Scale"), v_sizer); wxStaticText* size_Label {nullptr}; - add_label(&size_Label, L("Size"), v_sizer); +#if ENABLE_WORLD_COORDINATE + add_label(&size_Label, L("Size [World]"), v_sizer); +#else + add_label(&size_Label, L("Size"), v_sizer); +#endif // ENABLE_WORLD_COORDINATE if (wxOSX) set_font_and_background_style(size_Label, wxGetApp().normal_font()); sizer->Add(v_sizer, 0, wxLEFT, border); @@ -479,11 +483,18 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : #if ENABLE_WORLD_COORDINATE GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - if (selection.is_single_volume_or_modifier()) + if (selection.is_single_volume_or_modifier()) { + const bool is_left_handed = selection.get_first_volume()->get_volume_transformation().is_left_handed(); const_cast(selection.get_first_volume())->set_volume_scaling_factor(Vec3d::Ones()); + if (is_left_handed) + const_cast(selection.get_first_volume())->set_volume_mirror({ -1.0 , 1.0, 1.0 }); + } else if (selection.is_single_full_instance()) { + const bool is_left_handed = selection.get_first_volume()->get_instance_transformation().is_left_handed(); for (unsigned int idx : selection.get_volume_idxs()) { const_cast(selection.get_volume(idx))->set_instance_scaling_factor(Vec3d::Ones()); + if (is_left_handed) + const_cast(selection.get_volume(idx))->set_instance_mirror({ -1.0 , 1.0, 1.0 }); } } else @@ -712,21 +723,21 @@ void ObjectManipulation::update_settings_value(const Selection& selection) #if ENABLE_WORLD_COORDINATE if (is_world_coordinates()) { m_new_position = volume->get_instance_offset(); - m_new_scale_label_string = L("Scale"); - m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); + m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0; + m_new_rotate_label_string = L("Rotate (relative)"); #else if (m_world_coordinates) { m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0; m_new_size = selection.get_scaled_instance_bounding_box().size(); -#endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); +#endif // ENABLE_WORLD_COORDINATE m_new_rotation = Vec3d::Zero(); } else { #if ENABLE_WORLD_COORDINATE - m_new_move_label_string = L("Translate"); - m_new_rotate_label_string = L("Rotate"); + m_new_move_label_string = L("Translate (relative) [World]"); + m_new_rotate_label_string = L("Rotate (relative)"); m_new_position = Vec3d::Zero(); m_new_rotation = Vec3d::Zero(); m_new_scale = Vec3d(100.0, 100.0, 100.0); @@ -768,15 +779,15 @@ void ObjectManipulation::update_settings_value(const Selection& selection) const Vec3d& offset = trafo.get_offset(); m_new_position = offset; - m_new_rotate_label_string = L("Rotate"); + m_new_rotate_label_string = L("Rotate (relative)"); m_new_scale_label_string = L("Scale"); m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_rotation = Vec3d::Zero(); m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); } else if (is_local_coordinates()) { - m_new_move_label_string = L("Translate"); - m_new_rotate_label_string = L("Rotate"); + m_new_move_label_string = L("Translate (relative) [World]"); + m_new_rotate_label_string = L("Rotate (relative)"); m_new_position = Vec3d::Zero(); m_new_rotation = Vec3d::Zero(); m_new_scale = volume->get_volume_scaling_factor() * 100.0; @@ -785,7 +796,11 @@ void ObjectManipulation::update_settings_value(const Selection& selection) else { #endif // ENABLE_WORLD_COORDINATE m_new_position = volume->get_volume_offset(); +#if ENABLE_WORLD_COORDINATE + m_new_rotate_label_string = L("Rotate (relative)"); +#else m_new_rotate_label_string = L("Rotate"); +#endif // ENABLE_WORLD_COORDINATE m_new_rotation = Vec3d::Zero(); #if ENABLE_WORLD_COORDINATE m_new_scale_label_string = L("Scale"); @@ -1221,10 +1236,8 @@ void ObjectManipulation::change_scale_value(int axis, double value) scale = scale.cwiseQuotient(ref_scale); ref_scale = Vec3d::Ones(); } - else if (selection.is_single_full_instance()) { - scale = scale.cwiseQuotient(ref_scale); - ref_scale = Vec3d::Ones(); - } + else if (selection.is_single_full_instance()) + ref_scale = 100.0 * Vec3d::Ones(); this->do_scale(axis, scale.cwiseQuotient(ref_scale)); #else @@ -1276,9 +1289,9 @@ void ObjectManipulation::change_size_value(int axis, double value) else if (selection.is_single_full_instance()) { #if ENABLE_WORLD_COORDINATE if (is_world_coordinates()) - ref_size = selection.get_unscaled_instance_bounding_box().size(); - size = size.cwiseQuotient(ref_size); - ref_size = Vec3d::Ones(); + ref_size = selection.get_full_unscaled_instance_bounding_box().size(); + else + ref_size = selection.get_full_unscaled_instance_local_bounding_box().size(); #else ref_size = m_world_coordinates ? selection.get_unscaled_instance_bounding_box().size() : @@ -1311,8 +1324,7 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const else if (is_instance_coordinates()) transformation_type.set_instance(); - if (!(selection.is_single_volume_or_modifier() && is_local_coordinates()) && - !(selection.is_single_full_instance() && is_instance_coordinates())) + if (selection.is_single_volume_or_modifier() && !is_local_coordinates()) transformation_type.set_relative(); const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 5678008d34..dc016f2141 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -969,7 +969,7 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement); } else - transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); + transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); } else { if (transformation_type.local() && transformation_type.absolute()) { @@ -1066,7 +1066,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot)); } else - transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + transform_instance_relative_world(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -1471,6 +1471,26 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation const VolumeCache& volume_data = m_cache.volumes_data[i]; const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + Vec3d relative_scale = scale; + + if (transformation_type.absolute()) { + if (m_mode == Instance) { + if (is_single_full_instance()) { + BoundingBoxf3 current_box = m_box.get_bounding_box(); + BoundingBoxf3 original_box; + if (transformation_type.world()) + original_box = get_full_unscaled_instance_bounding_box(); + else + original_box = get_full_unscaled_instance_local_bounding_box(); + + relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(current_box.size()); + transformation_type.set_relative(); + } + } + else { + } + } + if (m_mode == Instance) { if (transformation_type.instance()) { const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); @@ -1478,11 +1498,11 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation Matrix3d inst_rotation, inst_scale; inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + inst_rotation * translation); - const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(scale); + const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale); v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot)); } else - transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center); + transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -1509,9 +1529,9 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - synchronize_unselected_instances(SyncRotationType::NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (m_mode == Volume) - synchronize_unselected_volumes(); + synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH ensure_on_bed(); @@ -3297,7 +3317,7 @@ void Selection::paste_objects_from_clipboard() } #if ENABLE_WORLD_COORDINATE -void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, +void Selection::transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot) { assert(transformation_type.relative()); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 36f973839d..29398eabfd 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -514,7 +514,7 @@ private: void paste_objects_from_clipboard(); #if ENABLE_WORLD_COORDINATE - void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + void transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3a69bcee14..e9c8547745 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1495,6 +1495,7 @@ void TabPrint::build() page = add_options_page(L("Support material"), "support"); category_path = "support-material_1698#"; optgroup = page->new_optgroup(L("Support material")); + optgroup->append_single_option_line("check_for_issues_mode", category_path + "check-for-issues-mode"); optgroup->append_single_option_line("support_material", category_path + "generate-support-material"); optgroup->append_single_option_line("support_material_auto", category_path + "auto-generated-supports"); optgroup->append_single_option_line("support_material_threshold", category_path + "overhang-threshold"); @@ -2190,10 +2191,9 @@ void TabFilament::clear_pages() void TabFilament::msw_rescale() { - for (const auto& over_opt : m_overrides_options) { - wxWindow* win = over_opt.second; - win->SetInitialSize(win->GetBestSize()); - } + for (const auto& over_opt : m_overrides_options) + if (wxWindow* win = over_opt.second) + win->SetInitialSize(win->GetBestSize()); Tab::msw_rescale(); } diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 7640f32202..2b473ae0c6 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -257,7 +257,7 @@ bool AppUpdateDownloadDialog::run_after_download() const boost::filesystem::path AppUpdateDownloadDialog::get_download_path() const { boost::system::error_code ec; - std::string input = GUI::format(txtctrl_path->GetValue()); + std::string input = GUI::into_u8(txtctrl_path->GetValue()); boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(input), ec); if (ec) dir = boost::filesystem::path(input);