diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c5be1d49f..008f9e9563 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -493,7 +493,8 @@ if (APPLE) endif () if(MSVC) -# 添加编译选项,忽略警告 C4305 (格式转换截断) +# Ignore truncating casts in initializers & constructors +# https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4305 add_compile_options(/wd4305) endif() diff --git a/resources/profiles/Qidi/filament/Q2/Generic PC @Q2.json b/resources/profiles/Qidi/filament/Q2/Generic PC @Q2.json index fb50534800..e3fee379ff 100644 --- a/resources/profiles/Qidi/filament/Q2/Generic PC @Q2.json +++ b/resources/profiles/Qidi/filament/Q2/Generic PC @Q2.json @@ -4,7 +4,7 @@ "inherits": "fdm_filament_q_common", "from": "system", "setting_id": "GFSA04", - "filament_id": "GFB99", + "filament_id": "QD_1_0_23", "instantiation": "false", "box_temperature_range_high": [ "65" diff --git a/resources/profiles/Qidi/filament/Q2/Generic PC @Q2C.json b/resources/profiles/Qidi/filament/Q2/Generic PC @Q2C.json index b23b635181..ccdfdddd3c 100644 --- a/resources/profiles/Qidi/filament/Q2/Generic PC @Q2C.json +++ b/resources/profiles/Qidi/filament/Q2/Generic PC @Q2C.json @@ -1,6 +1,6 @@ { "type": "filament", - "filament_id": "GFB99", + "filament_id": "QD_2_0_23", "setting_id": "GFSA04", "name": "Generic PC@Q2C-Series", "from": "system", diff --git a/resources/profiles/Qidi/filament/X4/Generic PC @X-Max 4.json b/resources/profiles/Qidi/filament/X4/Generic PC @X-Max 4.json index ffebfa765f..21dc071697 100644 --- a/resources/profiles/Qidi/filament/X4/Generic PC @X-Max 4.json +++ b/resources/profiles/Qidi/filament/X4/Generic PC @X-Max 4.json @@ -1,6 +1,6 @@ { "type": "filament", - "filament_id": "GFB99", + "filament_id": "QD_3_0_23", "setting_id": "GFSA04", "name": "Generic PC@X-Max 4-Series", "from": "system", diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp index a3e6cd21b0..726ee2ffd8 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp @@ -23,10 +23,11 @@ template<> struct hash namespace Slic3r { -void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object) +void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object, const std::function& throw_on_cancel) { const auto& config = print_object->config(); - if (!config.interlocking_beam) { + // Check if interlocking is enabled, and avoid errors like division by zero due to invalid configuration. + if (!config.interlocking_beam || config.interlocking_beam_layer_count < 1 || config.interlocking_depth < 1 || config.interlocking_beam_width < EPSILON ) { return; } @@ -55,8 +56,10 @@ void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_o continue; } + throw_on_cancel(); + InterlockingGenerator gen(*print_object, region_a_index, region_b_index, beam_width, boundary_avoidance, rotation, cell_size, beam_layer_count, - interface_dilation, air_dilation, air_filtering); + interface_dilation, air_dilation, air_filtering, throw_on_cancel); gen.generateInterlockingStructure(); } } @@ -108,12 +111,14 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set } } for (auto& near_interlock : near_interlock_per_layer) { + throw_on_cancel(); near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect); polygons_rotate(near_interlock, rotation); } // Only alter layers when they are present in both meshes, zip should take care if that. for (size_t layer_nr = 0; layer_nr < print_object.layer_count(); layer_nr++){ + throw_on_cancel(); auto layer = print_object.get_layer(layer_nr); ExPolygons polys_a = to_expolygons(layer->get_region(region_a_index)->slices.surfaces); ExPolygons polys_b = to_expolygons(layer->get_region(region_b_index)->slices.surfaces); @@ -199,7 +204,8 @@ void InterlockingGenerator::addBoundaryCells(const std::vector& lay const DilationKernel& kernel, std::unordered_set& cells) const { - auto voxel_emplacer = [&cells](GridPoint3 p) { + auto voxel_emplacer = [this, &cells](GridPoint3 p) { + this->throw_on_cancel(); if (p.z() < 0) { return true; } @@ -313,6 +319,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s for (size_t region_idx = 0; region_idx < 2; region_idx++) { const size_t region = (region_idx == 0) ? region_a_index : region_b_index; for (size_t layer_nr = 0; layer_nr < max_layer_count; layer_nr++) { + throw_on_cancel(); ExPolygons layer_outlines = layer_regions[layer_nr]; expolygons_rotate(layer_outlines, unapply_rotation); diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp index 6f331fb8ef..e6b79f9bc8 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp @@ -45,7 +45,7 @@ public: /*! * Generate an interlocking structure between each two adjacent meshes. */ - static void generate_interlocking_structure(PrintObject* print_object); + static void generate_interlocking_structure(PrintObject* print_object, const std::function& throw_on_cancel); private: /*! @@ -75,7 +75,8 @@ private: const coord_t beam_layer_count, const DilationKernel& interface_dilation, const DilationKernel& air_dilation, - const bool air_filtering) + const bool air_filtering, + const std::function& throw_on_cancel) : print_object(print_object) , region_a_index(region_a_index) , region_b_index(region_b_index) @@ -88,6 +89,7 @@ private: , interface_dilation(interface_dilation) , air_dilation(air_dilation) , air_filtering(air_filtering) + , throw_on_cancel(throw_on_cancel) {} /*! Given two polygons, return the parts that border on air, and grow 'perpendicular' up to 'detect' distance. @@ -165,6 +167,8 @@ private: // Whether to fully remove all of the interlocking cells which would be visible on the outside. If no air filtering then those cells // will be cut off midway in a beam. const bool air_filtering; + + const std::function& throw_on_cancel; }; } // namespace Slic3r diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 532307414d..2d67ac0939 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1212,7 +1212,7 @@ void PrintObject::slice_volumes() apply_fuzzy_skin_segmentation(*this, [print]() { print->throw_if_canceled(); }); } - InterlockingGenerator::generate_interlocking_structure(this); + InterlockingGenerator::generate_interlocking_structure(this, [print]() { print->throw_if_canceled(); }); m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin"; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2eff0298c9..e83e461ea9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2835,6 +2835,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re DynamicPrintConfig& proj_cfg = wxGetApp().preset_bundle->project_config; float x = dynamic_cast(proj_cfg.option("wipe_tower_x"))->get_at(plate_id); float y = dynamic_cast(proj_cfg.option("wipe_tower_y"))->get_at(plate_id); + // Helper: persist corrected wipe tower position to config so the next slice uses valid coords. + auto persist_wipe_tower_pos = [&](float nx, float ny) { + ConfigOptionFloat cx(nx), cy(ny); + proj_cfg.option("wipe_tower_x")->set_at(&cx, plate_id, 0); + proj_cfg.option("wipe_tower_y")->set_at(&cy, plate_id, 0); + }; float w = dynamic_cast(m_config->option("prime_tower_width"))->value; float a = dynamic_cast(proj_cfg.option("wipe_tower_rotation_angle"))->value; @@ -2884,6 +2890,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re _set_warning_notification(EWarning::PreviewPrimeTowerOutside, true); x = new_x; y = new_y; + // Persist the correction to config so the next slice uses the valid position + persist_wipe_tower_pos(new_x, new_y); } @@ -2906,7 +2914,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_id)->get_build_volume(true); BoundingBox plate_bbox2d = BoundingBox(scaled(Vec2f(plate_bbox.min[0], plate_bbox.min[1])), scaled(Vec2f(plate_bbox.max[0], plate_bbox.max[1]))); Vec2f offset = WipeTower::move_box_inside_box(tower_bottom_bbox, plate_bbox2d, scaled(margin)); - int volume_idx_wipe_tower_new = m_volumes.load_real_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1), + // move_box_inside_box returns mm (already unscaled); apply directly. + // If the actual brim polygon is outside bounds, persist the correction to config. + float display_x = x + offset[0]; + float display_y = y + offset[1]; + if (offset.norm() > float(EPSILON)) + persist_wipe_tower_pos(display_x, display_y); + int volume_idx_wipe_tower_new = m_volumes.load_real_wipe_tower_preview(1000 + plate_id, display_x + plate_origin(0), display_y + plate_origin(1), current_print->wipe_tower_data().wipe_tower_mesh_data->real_wipe_tower_mesh, current_print->wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, true,a,/*!print->is_step_done(psWipeTower)*/ true, m_initialized); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 332dc4c1df..5be497059c 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -4074,6 +4074,13 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx) wt_x_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_X_POS); wt_y_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_Y_POS); } + // Clamp default position to fit within the actual plate dimensions so the wipe tower + // doesn't start outside the bed for printers smaller than the hardcoded defaults. + const double wt_default_margin = 2.; + const double wt_estimated_width = 60.; // conservative estimate matching prime_tower_width default + const double wt_estimated_depth = 20.; // conservative depth estimate + wt_x_opt.value = std::max(wt_default_margin, std::min(wt_x_opt.value, m_plate_width - wt_estimated_width - wt_default_margin)); + wt_y_opt.value = std::max(wt_default_margin, std::min(wt_y_opt.value, m_plate_depth - wt_estimated_depth - wt_default_margin)); dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_idx, 0); dynamic_cast(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_idx, 0); }