Merge branch 'main' into disable_arc_fitting

This commit is contained in:
SoftFever
2026-03-15 23:05:37 +08:00
committed by GitHub
9 changed files with 45 additions and 12 deletions

View File

@@ -493,7 +493,8 @@ if (APPLE)
endif () endif ()
if(MSVC) 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) add_compile_options(/wd4305)
endif() endif()

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_q_common", "inherits": "fdm_filament_q_common",
"from": "system", "from": "system",
"setting_id": "GFSA04", "setting_id": "GFSA04",
"filament_id": "GFB99", "filament_id": "QD_1_0_23",
"instantiation": "false", "instantiation": "false",
"box_temperature_range_high": [ "box_temperature_range_high": [
"65" "65"

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFB99", "filament_id": "QD_2_0_23",
"setting_id": "GFSA04", "setting_id": "GFSA04",
"name": "Generic PC@Q2C-Series", "name": "Generic PC@Q2C-Series",
"from": "system", "from": "system",

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFB99", "filament_id": "QD_3_0_23",
"setting_id": "GFSA04", "setting_id": "GFSA04",
"name": "Generic PC@X-Max 4-Series", "name": "Generic PC@X-Max 4-Series",
"from": "system", "from": "system",

View File

@@ -23,10 +23,11 @@ template<> struct hash<Slic3r::GridPoint3>
namespace Slic3r { namespace Slic3r {
void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object) void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object, const std::function<void()>& throw_on_cancel)
{ {
const auto& config = print_object->config(); 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; return;
} }
@@ -55,8 +56,10 @@ void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_o
continue; continue;
} }
throw_on_cancel();
InterlockingGenerator gen(*print_object, region_a_index, region_b_index, beam_width, boundary_avoidance, rotation, cell_size, beam_layer_count, 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(); gen.generateInterlockingStructure();
} }
} }
@@ -108,12 +111,14 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set<GridPoint3>
} }
} }
for (auto& near_interlock : near_interlock_per_layer) { for (auto& near_interlock : near_interlock_per_layer) {
throw_on_cancel();
near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect); near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect);
polygons_rotate(near_interlock, rotation); polygons_rotate(near_interlock, rotation);
} }
// Only alter layers when they are present in both meshes, zip should take care if that. // 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++){ 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); auto layer = print_object.get_layer(layer_nr);
ExPolygons polys_a = to_expolygons(layer->get_region(region_a_index)->slices.surfaces); 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); ExPolygons polys_b = to_expolygons(layer->get_region(region_b_index)->slices.surfaces);
@@ -199,7 +204,8 @@ void InterlockingGenerator::addBoundaryCells(const std::vector<ExPolygons>& lay
const DilationKernel& kernel, const DilationKernel& kernel,
std::unordered_set<GridPoint3>& cells) const std::unordered_set<GridPoint3>& cells) const
{ {
auto voxel_emplacer = [&cells](GridPoint3 p) { auto voxel_emplacer = [this, &cells](GridPoint3 p) {
this->throw_on_cancel();
if (p.z() < 0) { if (p.z() < 0) {
return true; return true;
} }
@@ -313,6 +319,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s
for (size_t region_idx = 0; region_idx < 2; region_idx++) { for (size_t region_idx = 0; region_idx < 2; region_idx++) {
const size_t region = (region_idx == 0) ? region_a_index : region_b_index; 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++) { for (size_t layer_nr = 0; layer_nr < max_layer_count; layer_nr++) {
throw_on_cancel();
ExPolygons layer_outlines = layer_regions[layer_nr]; ExPolygons layer_outlines = layer_regions[layer_nr];
expolygons_rotate(layer_outlines, unapply_rotation); expolygons_rotate(layer_outlines, unapply_rotation);

View File

@@ -45,7 +45,7 @@ public:
/*! /*!
* Generate an interlocking structure between each two adjacent meshes. * 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<void()>& throw_on_cancel);
private: private:
/*! /*!
@@ -75,7 +75,8 @@ private:
const coord_t beam_layer_count, const coord_t beam_layer_count,
const DilationKernel& interface_dilation, const DilationKernel& interface_dilation,
const DilationKernel& air_dilation, const DilationKernel& air_dilation,
const bool air_filtering) const bool air_filtering,
const std::function<void()>& throw_on_cancel)
: print_object(print_object) : print_object(print_object)
, region_a_index(region_a_index) , region_a_index(region_a_index)
, region_b_index(region_b_index) , region_b_index(region_b_index)
@@ -88,6 +89,7 @@ private:
, interface_dilation(interface_dilation) , interface_dilation(interface_dilation)
, air_dilation(air_dilation) , air_dilation(air_dilation)
, air_filtering(air_filtering) , 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. /*! 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 // 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. // will be cut off midway in a beam.
const bool air_filtering; const bool air_filtering;
const std::function<void()>& throw_on_cancel;
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@@ -1212,7 +1212,7 @@ void PrintObject::slice_volumes()
apply_fuzzy_skin_segmentation(*this, [print]() { print->throw_if_canceled(); }); 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(); m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin"; BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";

View File

@@ -2835,6 +2835,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
DynamicPrintConfig& proj_cfg = wxGetApp().preset_bundle->project_config; DynamicPrintConfig& proj_cfg = wxGetApp().preset_bundle->project_config;
float x = dynamic_cast<const ConfigOptionFloats*>(proj_cfg.option("wipe_tower_x"))->get_at(plate_id); float x = dynamic_cast<const ConfigOptionFloats*>(proj_cfg.option("wipe_tower_x"))->get_at(plate_id);
float y = dynamic_cast<const ConfigOptionFloats*>(proj_cfg.option("wipe_tower_y"))->get_at(plate_id); float y = dynamic_cast<const ConfigOptionFloats*>(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<ConfigOptionFloats>("wipe_tower_x")->set_at(&cx, plate_id, 0);
proj_cfg.option<ConfigOptionFloats>("wipe_tower_y")->set_at(&cy, plate_id, 0);
};
float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("prime_tower_width"))->value; float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("prime_tower_width"))->value;
float a = dynamic_cast<const ConfigOptionFloat*>(proj_cfg.option("wipe_tower_rotation_angle"))->value; float a = dynamic_cast<const ConfigOptionFloat*>(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); _set_warning_notification(EWarning::PreviewPrimeTowerOutside, true);
x = new_x; x = new_x;
y = new_y; 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); 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]))); 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)); 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_wipe_tower_mesh,
current_print->wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, current_print->wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh,
true,a,/*!print->is_step_done(psWipeTower)*/ true, m_initialized); true,a,/*!print->is_step_done(psWipeTower)*/ true, m_initialized);

View File

@@ -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_x_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_X_POS);
wt_y_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_Y_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<ConfigOptionFloats *>(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_idx, 0); dynamic_cast<ConfigOptionFloats *>(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_idx, 0);
dynamic_cast<ConfigOptionFloats *>(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_idx, 0); dynamic_cast<ConfigOptionFloats *>(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_idx, 0);
} }