From 2e08b19d6bc2efb24f7e167c29dd2995b088fdbc Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Fri, 31 Jul 2026 20:51:48 -0300 Subject: [PATCH 01/23] Outline MSAA (#14835) Co-authored-by: Ian Bassi --- resources/shaders/140/gouraud.fs | 97 +++++++++++++++++++++++--------- resources/shaders/140/phong.fs | 79 ++++++++++++++++++++------ src/slic3r/GUI/3DScene.cpp | 78 ++++++++++++++++++++----- 3 files changed, 198 insertions(+), 56 deletions(-) diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index 728b7f942c..e099984b46 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -1,4 +1,7 @@ #version 140 +// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline). +// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture. +#extension GL_ARB_texture_multisample : enable const vec3 ZERO = vec3(0.0, 0.0, 0.0); //BBS: add grey and orange @@ -36,7 +39,14 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; +// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the +// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer. +#ifdef GL_ARB_texture_multisample +uniform sampler2DMS depth_tex; +uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off +#else uniform sampler2D depth_tex; +#endif uniform vec2 screen_size; #ifdef ENABLE_ENVIRONMENT_MAP @@ -99,45 +109,87 @@ float GetTolerance(float d, float k) return -k*(d+A)*(d+A)/B; } -float DetectSilho(vec2 fragCoord, vec2 dir) +// Depth of sample s at integer pixel coord. +#ifdef GL_ARB_texture_multisample +float FetchDepth(ivec2 coord, int s) +{ + // texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE). + ivec2 sz = textureSize(depth_tex); + return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r); +} +#else +float FetchDepth(ivec2 coord, int s) +{ + return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r); +} +#endif + +float DetectSilho(ivec2 coord, ivec2 dir, int s) { // ------------------------------------------- - // x0 ___ x1----o - // :\ : + // x0 ___ x1----o + // :\ : // r0 : \ : r1 - // : \ : + // : \ : // o---x2 ___ x3 // // r0 and r1 are the differences between actual // and expected (as if x0..3 where on the same // plane) depth values. // ------------------------------------------- - - float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r); - float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r); - float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r); - float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r); - + float x0 = FetchDepth(coord + dir*-2, s); + float x1 = FetchDepth(coord + dir*-1, s); + float x2 = FetchDepth(coord, s); + float x3 = FetchDepth(coord + dir* 1, s); + float d0 = (x1-x0); float d1 = (x2-x3); - + float r0 = x1 + d0 - x2; float r1 = x2 + d1 - x1; - - float tol = GetTolerance(x2, 0.04); - - return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); + float tol = GetTolerance(x2, 0.04); + + return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); } -float DetectSilho(vec2 fragCoord) +float DetectSilho(ivec2 coord, int s) { return max( - DetectSilho(fragCoord, vec2(1,0)), // Horizontal - DetectSilho(fragCoord, vec2(0,1)) // Vertical + DetectSilho(coord, ivec2(1,0), s), // Horizontal + DetectSilho(coord, ivec2(0,1), s) // Vertical ); } +// Full response of one sample. Reduce the max() per sample and average only afterwards: +// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines. +float DetectSilhoSample(ivec2 coord, int s) +{ + float v = DetectSilho(coord, s); + // Makes silhouettes thicker. + for (int i = 1; i <= INFLATE; ++i) + { + v = max(v, DetectSilho(coord + ivec2(i, 0), s)); + v = max(v, DetectSilho(coord + ivec2(0, i), s)); + } + return v; +} + +// Average the per-sample coverage into the sub-pixel anti-aliasing of the line. +float DetectSilho(vec2 fragCoord) +{ + ivec2 coord = ivec2(fragCoord); +#ifdef GL_ARB_texture_multisample + int n = max(msaa_samples, 1); +#else + const int n = 1; +#endif + float acc = 0.0; + for (int s = 0; s < n; ++s) + acc += DetectSilhoSample(coord, s); + return acc / float(n); +} + // Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is // occluded from the light in the shadow map. 3x3 PCF softens the edges. float shadow_shade() @@ -224,14 +276,7 @@ void main() //BBS: add outline_color if (is_outline) { color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a); - vec2 fragCoord = gl_FragCoord.xy; - float s = DetectSilho(fragCoord); - // Makes silhouettes thicker. - for(int i=1;i<=INFLATE; i++) - { - s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0))); - s = max(s, DetectSilho(fragCoord.xy + vec2(0, i))); - } + float s = DetectSilho(gl_FragCoord.xy); if (s < 0.01) discard; out_color = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a); diff --git a/resources/shaders/140/phong.fs b/resources/shaders/140/phong.fs index bbde72592c..f847763658 100644 --- a/resources/shaders/140/phong.fs +++ b/resources/shaders/140/phong.fs @@ -1,4 +1,7 @@ #version 140 +// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline). +// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture. +#extension GL_ARB_texture_multisample : enable const vec3 ZERO = vec3(0.0, 0.0, 0.0); const vec3 LightRed = vec3(0.78, 0.0, 0.0); @@ -51,7 +54,14 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; +// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the +// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer. +#ifdef GL_ARB_texture_multisample +uniform sampler2DMS depth_tex; +uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off +#else uniform sampler2D depth_tex; +#endif uniform vec2 screen_size; #ifdef ENABLE_ENVIRONMENT_MAP @@ -100,12 +110,27 @@ float GetTolerance(float d, float k) return -k*(d+A)*(d+A)/B; } -float DetectSilho(vec2 fragCoord, vec2 dir) +// Depth of sample s at integer pixel coord. +#ifdef GL_ARB_texture_multisample +float FetchDepth(ivec2 coord, int s) { - float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r); - float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r); - float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r); - float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r); + // texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE). + ivec2 sz = textureSize(depth_tex); + return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r); +} +#else +float FetchDepth(ivec2 coord, int s) +{ + return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r); +} +#endif + +float DetectSilho(ivec2 coord, ivec2 dir, int s) +{ + float x0 = FetchDepth(coord + dir*-2, s); + float x1 = FetchDepth(coord + dir*-1, s); + float x2 = FetchDepth(coord, s); + float x3 = FetchDepth(coord + dir* 1, s); float d0 = (x1-x0); float d1 = (x2-x3); @@ -116,17 +141,45 @@ float DetectSilho(vec2 fragCoord, vec2 dir) float tol = GetTolerance(x2, 0.04); return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); - } -float DetectSilho(vec2 fragCoord) +float DetectSilho(ivec2 coord, int s) { return max( - DetectSilho(fragCoord, vec2(1,0)), - DetectSilho(fragCoord, vec2(0,1)) + DetectSilho(coord, ivec2(1,0), s), + DetectSilho(coord, ivec2(0,1), s) ); } +// Full response of one sample. Reduce the max() per sample and average only afterwards: +// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines. +float DetectSilhoSample(ivec2 coord, int s) +{ + float v = DetectSilho(coord, s); + // Makes silhouettes thicker. + for (int i = 1; i <= INFLATE; ++i) + { + v = max(v, DetectSilho(coord + ivec2(i, 0), s)); + v = max(v, DetectSilho(coord + ivec2(0, i), s)); + } + return v; +} + +// Average the per-sample coverage into the sub-pixel anti-aliasing of the line. +float DetectSilho(vec2 fragCoord) +{ + ivec2 coord = ivec2(fragCoord); +#ifdef GL_ARB_texture_multisample + int n = max(msaa_samples, 1); +#else + const int n = 1; +#endif + float acc = 0.0; + for (int s = 0; s < n; ++s) + acc += DetectSilhoSample(coord, s); + return acc / float(n); +} + float compute_ssao_factor(vec3 normal, vec3 view_dir, vec3 eye_pos) { vec3 normal_dx = dFdx(normal); @@ -270,13 +323,7 @@ void main() if (is_outline) { vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade; vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a); - vec2 fragCoord = gl_FragCoord.xy; - float s = DetectSilho(fragCoord); - for(int i=1;i<=INFLATE; i++) - { - s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0))); - s = max(s, DetectSilho(fragCoord.xy + vec2(0, i))); - } + float s = DetectSilho(gl_FragCoord.xy); if (s < 0.01) discard; out_color = vec4(mix(shaded_color.rgb, getBackfaceColor(shaded_color.rgb), s), shaded_color.a); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index b52a520200..bf5d1f2421 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -70,6 +70,9 @@ float FullTransparentModdifiedToFixAlpha = 0.3f; // value like 0.18f could not because in C++ (int)(0.18f * 255) == 45 however in OpenGL it renders this as 46 // which breaks the `SelectMachineDialog::record_edge_pixels_data()` function! float FULL_BLACK_THRESHOLD = 0.2f; +// Keep depth_tex away from texture unit 0 to avoid sampler-type aliasing with +// shadow/environment samplers when realistic view is disabled. +static constexpr int OUTLINE_DEPTH_TEX_UNIT = 5; Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) { @@ -518,6 +521,37 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glStencilMask(0xFF)); glsafe(::glDisable(GL_STENCIL_TEST)); // render the outline using depth buffer and discard the pixels that are not on the outline + // The silhouette is resolved per sample in the shader (see DetectSilho in gouraud.fs/phong.fs). + // That needs the GL 3.2 entry points and a shader that declares depth_tex as sampler2DMS, which + // only the 140 ones do and only under GL_ARB_texture_multisample - so ask the compiled program + // rather than the GL version, or a sampler2D ends up bound to a multisample texture. + // Only the Arb branch below allocates a multisample texture, so keep the target consistent with it. + const bool use_msaa_outline = framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb && + GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 2) && + shader->get_uniform_location("msaa_samples") >= 0; + const GLenum depth_tex_target = use_msaa_outline ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + // Keep the depth texture off image unit 0. The object shaders leave shadow_map (and + // environment_tex) at the default sampler value 0 whenever the shadow pass is skipped - which is + // the case with realistic view off - and GL forbids two sampler types referring to the same image + // unit. A sampler2DMS on unit 0 then makes every draw fail with INVALID_OPERATION on drivers that + // enforce it (Mesa), i.e. the model disappears entirely. Unit 5 is unused (shadow_map takes 4). + const int depth_tex_unit = OUTLINE_DEPTH_TEX_UNIT; + int aa_samples = 1; + if (use_msaa_outline) { + if (const AppConfig* app_config = GUI::wxGetApp().app_config; app_config != nullptr) { + const std::string value = app_config->get(SETTING_OPENGL_AA_SAMPLES); + if (value == "2" || value == "4" || value == "8" || value == "16") + aa_samples = ::atoi(value.c_str()); + } + // Never request more samples than the driver supports for depth textures (a 1-sample texture + // is used when MSAA is disabled, keeping a single code path for the sampler2DMS shader). + GLint max_samples = 1; + glsafe(::glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &max_samples)); + if (aa_samples > max_samples) + aa_samples = max_samples < 1 ? 1 : max_samples; + if (aa_samples < 1) + aa_samples = 1; + } // 1st. render pass, render the model into a separate render target that has only depth buffer GLuint depth_fbo = 0; GLuint depth_tex = 0; @@ -525,21 +559,26 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glGenFramebuffers(1, &depth_fbo)); glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo)); - glActiveTexture(GL_TEXTURE0); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); glsafe(::glGenTextures(1, &depth_tex)); - glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); + glsafe(::glBindTexture(depth_tex_target, depth_tex)); + if (use_msaa_outline) { + // Multisample textures do not take filter/wrap parameters. + glsafe(::glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, aa_samples, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), GL_TRUE)); + } else { + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); + } - glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_tex_target, depth_tex, 0)); } else { glsafe(::glGenFramebuffersEXT(1, &depth_fbo)); glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, depth_fbo)); - glActiveTexture(GL_TEXTURE0); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); glsafe(::glGenTextures(1, &depth_tex)); glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); @@ -550,12 +589,15 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0)); } + // Unbind before drawing: the texture is this framebuffer's depth attachment, so leaving it bound + // to a sampled unit would be a feedback loop. + glsafe(::glBindTexture(depth_tex_target, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); if (tverts_range == std::make_pair(0, -1)) model.render(shader); else model.render(this->tverts_range, shader); - glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); // 2nd. render pass, just a normal render with the depth buffer passed as a texture if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) { @@ -565,13 +607,17 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) } shader->set_uniform("is_outline", true); shader->set_uniform("screen_size", Vec2f{cnv_size.get_width(), cnv_size.get_height()}); - glActiveTexture(GL_TEXTURE0); - glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); - shader->set_uniform("depth_tex", 0); + shader->set_uniform("msaa_samples", aa_samples); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); + glsafe(::glBindTexture(depth_tex_target, depth_tex)); + glsafe(::glActiveTexture(GL_TEXTURE0)); + shader->set_uniform("depth_tex", depth_tex_unit); simple_render(shader, model_objects, colors); // Some clean up to do - glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); + glsafe(::glBindTexture(depth_tex_target, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0)); shader->set_uniform("is_outline", false); if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) { glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); @@ -1075,6 +1121,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, const float support_normal_z = get_selection_support_normal_z(); + // Prime depth_tex on every frame so non-outline draws do not keep the + // default sampler unit 0, which can conflict with other sampler types. + shader->set_uniform("depth_tex", OUTLINE_DEPTH_TEX_UNIT); + for (GLVolumeWithIdAndZ& volume : to_render) { #if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT if (type == ERenderType::Transparent) { From 477208a9694a2ba3198538eab3b33f0bda98d90a Mon Sep 17 00:00:00 2001 From: yw4z Date: Sat, 1 Aug 2026 06:28:07 +0300 Subject: [PATCH 02/23] Remove borders and paddings from native controls on Linux (#14873) * init * update * Update SpinInput.cpp * possible fix for em_unit * button alignment * match titlebar height * revert em_value for macOS and Windows * Update GUI_Utils.hpp * Merge branch 'main' into linux-black-borders-2 * Revert "button alignment" This reverts commit 3fc7461071cd8b2bd1b701151c3d11af579b5129. * Revert "match titlebar height" This reverts commit c4aa1d9f1e08925716f37e78795c1708e93cb194. * revert dpi changes * match platform tags * remove radio box borders * Fix code indent --- src/slic3r/GUI/GUI_Utils.cpp | 54 ++++++++++++++++++++++++- src/slic3r/GUI/GUI_Utils.hpp | 5 ++- src/slic3r/GUI/PresetComboBoxes.cpp | 3 ++ src/slic3r/GUI/Widgets/CheckBox.cpp | 4 +- src/slic3r/GUI/Widgets/RadioBox.cpp | 5 +++ src/slic3r/GUI/Widgets/SpinInput.cpp | 9 +++++ src/slic3r/GUI/Widgets/SwitchButton.cpp | 4 +- src/slic3r/GUI/Widgets/TextInput.cpp | 9 +++++ src/slic3r/GUI/wxExtensions.cpp | 4 ++ 9 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 697eefea0b..cb8ba45c6b 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -548,7 +548,7 @@ void RemoveButtonBorder(wxWindow* win) GtkCssProvider* provider = gtk_css_provider_new(); const char* css = - "button {" + "button, button:hover, button:active, button:focus {" " border: none;" " outline: none;" " box-shadow: none;" @@ -589,6 +589,58 @@ void RemoveButtonBorder(wxWindow* win) ); #endif } + +void RemoveInputBorder(wxWindow* win) +{ + GtkWidget* widget = win->GetHandle(); + if (!widget) return; + +#if GTK_CHECK_VERSION(3, 0, 0) + // GTK3+: use CSS provider + GtkCssProvider* provider = gtk_css_provider_new(); + + // Target 'entry' and its inner subnodes (like text selection areas) + const char* css = + "entry, entry text, entry undershoot {" + " border: none;" + " outline: none;" + " box-shadow: none;" + " padding: 0px;" + " margin: 0px;" + " min-height: 0px;" + " min-width: 0px;" + " background: none;" + "}"; + +#if GTK_CHECK_VERSION(4, 0, 0) + // GTK4 + gtk_css_provider_load_from_data(provider, css, -1); +#else + // GTK3 + gtk_css_provider_load_from_data(provider, css, -1, nullptr); +#endif + + GtkStyleContext* ctx = gtk_widget_get_style_context(widget); + gtk_style_context_add_provider( + ctx, + GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_USER + ); + g_object_unref(provider); + +#else + // GTK2: Target the x/y thickness of the entry widget + gtk_rc_parse_string( + "style \"no-padding-entry\" {" + " xthickness = 0" + " ythickness = 0" + " GtkEntry::inner-border = { 0, 0, 0, 0 }" + " GtkEntry::focus-line-width = 0" + "}" + "class \"GtkEntry\" style \"no-padding-entry\"" + ); +#endif +} #endif // __WXGTK__ #ifdef __linux__ diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 427ba9f0ad..890e8b9e1c 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -472,8 +472,9 @@ void dataview_remove_insets(wxDataViewCtrl* dv); void staticbox_remove_margin(wxStaticBox* sb); #endif -#ifdef __WXGTK3__ -void RemoveButtonBorder(wxWindow* win); +#ifdef __WXGTK__ +void RemoveButtonBorder(wxWindow* win); // for wxButton/wxBitmapToggleButton based controls (SwitchButton, CheckBox) +void RemoveInputBorder(wxWindow* win); // for TextCtrl based controls (TextInput, ComboBox, SpinInput..) #endif #if defined(__WXOSX__) || defined(__linux__) diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 8fdca030c6..c979fc3212 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -865,6 +865,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset clr_picker = new wxBitmapButton(parent, wxID_ANY, {}, wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), wxBU_EXACTFIT | wxBU_AUTODRAW | wxBORDER_NONE); clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); clr_picker->SetToolTip(_L("Click to select filament color")); +#ifdef __WXGTK__ + RemoveButtonBorder(clr_picker); +#endif clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { // Check if it's an official filament auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data()); diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp index 54e98887e7..91cbb8c4e1 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.cpp +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -2,7 +2,7 @@ #include "../wxExtensions.hpp" -#ifdef __WXGTK3__ +#ifdef __WXGTK__ #include "../GUI_Utils.hpp" #endif @@ -29,7 +29,7 @@ CheckBox::CheckBox(wxWindow *parent, int id) Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this); #endif -#ifdef __WXGTK3__ +#ifdef __WXGTK__ Slic3r::GUI::RemoveButtonBorder(this); #endif diff --git a/src/slic3r/GUI/Widgets/RadioBox.cpp b/src/slic3r/GUI/Widgets/RadioBox.cpp index a8a1d8a1ef..7f20b8724c 100644 --- a/src/slic3r/GUI/Widgets/RadioBox.cpp +++ b/src/slic3r/GUI/Widgets/RadioBox.cpp @@ -2,6 +2,10 @@ #include "../wxExtensions.hpp" +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + namespace Slic3r { namespace GUI { RadioBox::RadioBox(wxWindow *parent) @@ -15,6 +19,7 @@ RadioBox::RadioBox(wxWindow *parent) // Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); update(); #ifdef __WXGTK__ + Slic3r::GUI::RemoveButtonBorder(this); wxSize bestSize = GetBestSize(); bestSize.IncTo(m_on.GetBmpSize()); SetSize(bestSize); diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index ccd7a80447..fba5a45233 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -5,6 +5,10 @@ #include +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + BEGIN_EVENT_TABLE(SpinInput, StaticBox) EVT_KEY_DOWN(SpinInput::keyPressed) @@ -58,6 +62,11 @@ void SpinInput::Create(wxWindow *parent, state_handler.attach({&label_color, &text_color}); state_handler.update_binds(); text_ctrl = new TextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveInputBorder(text_ctrl); +#endif + text_ctrl->SetFont(Label::Body_14); text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp index 9e780c0f02..c391ddd017 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -12,7 +12,7 @@ #include "libslic3r/MacUtils.hpp" #endif -#ifdef __WXGTK3__ +#ifdef __WXGTK__ #include "../GUI_Utils.hpp" #endif @@ -37,7 +37,7 @@ SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id) Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); SetFont(Label::Body_12); -#ifdef __WXGTK3__ +#ifdef __WXGTK__ Slic3r::GUI::RemoveButtonBorder(this); #endif diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 362e4c99b3..49605e048d 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -6,6 +6,10 @@ #include #include +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + BEGIN_EVENT_TABLE(TextInput, StaticBox) EVT_PAINT(TextInput::paintEvent) @@ -60,6 +64,11 @@ void TextInput::Create(wxWindow * parent, state_handler.attach({&label_color, & text_color}); state_handler.update_binds(); text_ctrl = new TextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER); + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveInputBorder(text_ctrl); +#endif + text_ctrl->SetFont(Label::Body_14); text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index e40046c37d..2ca8f3cfbd 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1022,6 +1022,10 @@ ScalableButton::ScalableButton( wxWindow * parent, m_width = size.x * 10 / em; m_height= size.y * 10 / em; } + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveButtonBorder(this); +#endif } From 80e64f80a613967b411c03caeafdcf13d4e7e3c5 Mon Sep 17 00:00:00 2001 From: Kenneth Raplee <101818165+kenrap@users.noreply.github.com> Date: Sat, 1 Aug 2026 03:49:28 +0000 Subject: [PATCH 03/23] Fix 32-bit build in LayerResult::make_nop_layer_result (#15036) LayerResult's second field is typed size_t, so std::numeric_limits::max should also use size_t and not something related to coordinates for the layer_id. --- src/libslic3r/GCode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index acd5acb0a2..47abf6be85 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -184,7 +184,7 @@ struct LayerResult { // It is used for the pressure equalizer because it needs to buffer one layer back. bool nop_layer_result { false }; - static LayerResult make_nop_layer_result() { return {"", std::numeric_limits::max(), false, false, true}; } + static LayerResult make_nop_layer_result() { return {"", std::numeric_limits::max(), false, false, true}; } }; class GCode { From 95b781745dfffd458b703f6a743ba93416d5d354 Mon Sep 17 00:00:00 2001 From: "Dipl.-Ing. Raoul Rubien, BSc" Date: Sat, 1 Aug 2026 12:07:15 +0200 Subject: [PATCH 04/23] Fixes 4 Compiler Warnings (#10727) * fixes: may be used uninitialized [-Wmaybe-uninitialized] * fixes: arc_len_next may be used uninitialized [-Wmaybe-uninitialized] * review result: reverts {} initializer with = to keep code style consistent --- src/libslic3r/BoundingBox.hpp | 2 +- src/libslic3r/Fill/FillBase.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index 42f5220975..8aac3f1cb9 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -25,7 +25,7 @@ public: min(p1), max(p1), defined(false) { merge(p2); merge(p3); } template> - BoundingBoxBase(It from, It to) + BoundingBoxBase(It from, It to) : BoundingBoxBase() { construct(*this, from, to); } BoundingBoxBase(const PointsType &points) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 2606529099..45157ec42d 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -1857,12 +1857,12 @@ static inline void base_support_extend_infill_lines(Polylines &infill, BoundaryI const bool first = graph.first(cp); int extend_next_idx = -1; int extend_prev_idx = -1; - coord_t dist_y_prev; - coord_t dist_y_next; - double arc_len_prev; - double arc_len_next; + coord_t dist_y_prev = 0; + coord_t dist_y_next = 0; + double arc_len_prev = 0; + double arc_len_next = 0; - if (! graph.next_vertical(cp)){ + if (! graph.next_vertical(cp)) { size_t i = cp.point_idx; size_t j = next_idx_modulo(i, contour); while (j != cp.next_on_contour->point_idx) { From abb2ab8d3fb70a943b96f395d382dfdd03d2d43a Mon Sep 17 00:00:00 2001 From: GlauTech <33813227+GlauTechCo@users.noreply.github.com> Date: Sat, 1 Aug 2026 23:26:26 +0300 Subject: [PATCH 05/23] Update OrcaSlicer_tr.po (#15060) --- localization/i18n/tr/OrcaSlicer_tr.po | 624 +++++++++++++------------- 1 file changed, 311 insertions(+), 313 deletions(-) diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 7ef4d33cfd..fd1ad673af 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-07-29 17:40-0300\n" -"PO-Revision-Date: 2026-04-08 23:59+0300\n" +"PO-Revision-Date: 2026-08-01 20:32+0300\n" "Last-Translator: GlauTech\n" "Language-Team: \n" "Language: tr\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n==1) ? 0 : 1;\n" -"X-Generator: Po Translator App\n" +"X-Generator: Poedit 3.9\n" # AI Translated msgid "Main Extruder" @@ -84,10 +84,10 @@ msgid "Left Nozzle" msgstr "Sol Nozul" msgid "Left nozzle" -msgstr "Sol meme" +msgstr "Sol nozul" msgid "left nozzle" -msgstr "sol meme" +msgstr "sol nozul" msgid "Right Nozzle" msgstr "Sağ Nozul" @@ -96,7 +96,7 @@ msgid "Right nozzle" msgstr "Sağ nozul" msgid "right nozzle" -msgstr "sağ meme" +msgstr "sağ nozul" # AI Translated msgid "Main Hotend" @@ -818,7 +818,7 @@ msgid "Size" msgstr "Boyut" msgid "Uniform scale" -msgstr "düzgün ölçek" +msgstr "Orantılı ölçekleme" msgid "Planar" msgstr "Düzlemsel" @@ -1159,7 +1159,7 @@ msgid "Show wireframe" msgstr "Wireframe göster" msgid "Unable to apply when processing preview" -msgstr "İşlem önizlemesi sırasında uygulanamaz." +msgstr "Önizleme işlenirken uygulanamaz" msgid "Operation already cancelling. Please wait a few seconds." msgstr "İşlem zaten iptal ediliyor. Lütfen birkaç saniye bekleyin." @@ -1727,7 +1727,7 @@ msgid "Change file" msgstr "Dosyayı değiştir" msgid "Change to another SVG file." -msgstr "Başka bir .svg dosyasına geçin" +msgstr "Farklı bir SVG dosyası seç." msgid "Forget the file path" msgstr "Dosya yolunu unut" @@ -1754,7 +1754,7 @@ msgid "Save SVG file" msgstr "SVG dosyasını kaydet" msgid "Save as SVG file." -msgstr "'.svg' dosyası olarak kaydet" +msgstr "SVG dosyası olarak kaydet." msgid "Size in emboss direction." msgstr "Kabartma yönünde boyut." @@ -2430,7 +2430,7 @@ msgstr "Gizlilik Politikası Güncellemesi" # AI Translated #, c-format, boost-format msgid "your Orca Cloud profile (user ID: \"%s\")" -msgstr "Orca Cloud profiliniz (kullanıcı kimliği: \"%s\")" +msgstr "orca Cloud profiliniz (Kullanıcı ID: \"%s\")" # AI Translated msgid "your default profile" @@ -2991,22 +2991,22 @@ msgid "Auto orientation" msgstr "Otomatik yönlendirme" msgid "Auto orient the object to improve print quality" -msgstr "Baskı kalitesini artırmak için nesneyi otomatik olarak yönlendirin." +msgstr "Baskı kalitesini artırmak için nesneyi otomatik yönlendir" msgid "Edit" msgstr "Düzenle" msgid "Merge with" -msgstr "Şununla birleştir:" +msgstr "Şununla birleştir" msgid "Delete this filament" -msgstr "Bu filamanı sil" +msgstr "Bu filamenti sil" msgid "Select All" msgstr "Hepsini seç" msgid "Select all objects on the current plate" -msgstr "geçerli plakadaki tüm nesneleri seç" +msgstr "Mevcut plakadaki tüm nesneleri seç" msgid "Select All Plates" msgstr "Tüm Plakaları Seç" @@ -3018,7 +3018,7 @@ msgid "Delete All" msgstr "Hepsini sil" msgid "Delete all objects on the current plate" -msgstr "geçerli plakadaki tüm nesneleri sil" +msgstr "Mevcut tabladaki tüm nesneleri sil" msgid "Arrange" msgstr "Hizala" @@ -3410,7 +3410,7 @@ msgid "Invalid numeric." msgstr "Geçersiz sayı." msgid "One cell can only be copied to one or more cells in the same column." -msgstr "bir hücre aynı sütundaki yalnızca bir veya daha fazla hücreye kopyalanabilir" +msgstr "Bir hücre yalnızca aynı sütundaki bir veya daha fazla hücreye kopyalanabilir." msgid "Copying multiple cells is not supported." msgstr "Birden fazla hücre kopyalama desteklenmiyor." @@ -3478,13 +3478,13 @@ msgid "More" msgstr "Daha" msgid "Open Preferences" -msgstr "Tercihler'i açın." +msgstr "Tercihleri Aç" msgid "Open next tip" -msgstr "Sonraki ipucunu açın." +msgstr "Sonraki ipucunu aç" msgid "Open documentation in web browser" -msgstr "Belgeleri web tarayıcısında açın." +msgstr "Dokümantasyonu web tarayıcısında aç" msgid "Color" msgstr "Renk" @@ -3517,7 +3517,7 @@ msgid "Jump to layer" msgstr "Katmana Atla" msgid "Please enter the layer number." -msgstr "Lütfen katman numarasını girin" +msgstr "Lütfen katman numarasını girin." msgid "Add Pause" msgstr "Duraklatma Ekle" @@ -3605,7 +3605,7 @@ msgid "Choose an AMS slot then press \"Load\" or \"Unload\" button to automatica msgstr "Bir AMS yuvası seçin ve filamentleri otomatik olarak yüklemek veya boşaltmak için “Yükle” veya “Boşalt” düğmesine basın." msgid "Filament type is unknown which is required to perform this action. Please set target filament's informations." -msgstr "Bu eylemi gerçekleştirmek için gereken filaman türü bilinmiyor. Lütfen hedef filamanın bilgilerini ayarlayın." +msgstr "Bu eylemi gerçekleştirmek için gereken filament türü bilinmiyor. Lütfen hedef filamentin bilgilerini ayarlayın." # AI Translated msgid "AMS has not been initialized. Please initialize it before use." @@ -3759,10 +3759,10 @@ msgid "Switch track at Filament Track Switch" msgstr "Filament Track Switch'te hattı değiştir" msgid "The maximum temperature cannot exceed " -msgstr "Maksimum sıcaklık aşılamaz" +msgstr "Maksimum sıcaklık şu değeri aşamaz: " msgid "The minmum temperature should not be less than " -msgstr "Minimum sıcaklık," +msgstr "Minimum sıcaklık şu değerden az olamaz: " # AI Translated msgid "Type to filter..." @@ -4284,7 +4284,7 @@ msgid "" "The nozzle flow is not set. Please set the nozzle flow rate before editing the filament.\n" "'Device -> Print parts'" msgstr "" -"Meme akışı ayarlanmamış. Lütfen filamenti düzenlemeden önce nozül akış hızını ayarlayın.\n" +"Nozul akışı ayarlanmamış. Lütfen filamenti düzenlemeden önce nozul akış hızını ayarlayın.\n" "'Cihaz -> Parçaları yazdır'" msgid "AMS" @@ -4370,7 +4370,7 @@ msgid "" "And you can click it to modify" msgstr "" "Üst yarı alanı: Orijinal\n" -"Alt yarı alan: Eşleme kaldırıldığında orijinal projedeki filaman kullanılacaktır.\n" +"Alt yarı alan: Eşleme kaldırıldığında orijinal projedeki filament kullanılacaktır.\n" "Ve değiştirmek için tıklayabilirsiniz" msgid "" @@ -4471,7 +4471,7 @@ msgstr "AMS'yi Etkinleştirme" # AI Translated msgid "Print using filament on external spool." -msgstr "Harici makaradaki filamenti kullanarak yazdırma" +msgstr "Harici makaradaki filamenti kullanarak yazdır." msgid "Print with filament in AMS" msgstr "AMS içerisindeki filamentlerle yazdırma" @@ -4508,7 +4508,7 @@ msgid "" "When the current filament runs out, the printer will use identical filament to continue printing.\n" "*Identical filament: same brand, type and color." msgstr "" -"Mevcut filaman bittiğinde yazıcı, yazdırmaya devam etmek için aynı filamanı kullanacaktır.\n" +"Mevcut filament bittiğinde yazıcı, yazdırmaya devam etmek için aynı filamenti kullanacaktır.\n" "*Aynı filament: aynı marka, tip ve renkte." msgid "DRY" @@ -4527,14 +4527,14 @@ msgid "The AMS will automatically read the filament information when inserting a msgstr "AMS, yeni bir Bambu Lab filamenti takıldığında filament bilgilerini otomatik olarak okuyacaktır. Bu yaklaşık 20 saniye sürer." msgid "Note: if a new filament is inserted during printing, the AMS will not automatically read any information until printing is completed." -msgstr "Not: Yazdırma sırasında yeni bir filaman takılırsa AMS, yazdırma tamamlanana kadar herhangi bir bilgiyi otomatik olarak okumayacaktır." +msgstr "Not: Yazdırma sırasında yeni bir filament takılırsa AMS, yazdırma tamamlanana kadar herhangi bir bilgiyi otomatik olarak okumayacaktır." msgid "When inserting a new filament, the AMS will not automatically read its information, leaving it blank for you to enter manually." msgstr "Yeni bir filament yerleştirirken AMS, bilgileri otomatik olarak okumaz ve manuel olarak girmeniz için boş bırakır." # AI Translated msgid "Update on startup" -msgstr "Başlangıçta güncelle" +msgstr "Açılışta güncelle" msgid "The AMS will automatically read the information of inserted filament on start-up. It will take about 1 minute. The reading process will rotate the filament spools." msgstr "AMS, başlangıçta takılan filamentin bilgilerini otomatik olarak okuyacaktır. Yaklaşık 1 dakika sürecektir. Okuma işlemi filament makaralarını saracaktır." @@ -4570,7 +4570,7 @@ msgid "The printer is busy and cannot switch AMS type." msgstr "Yazıcı meşgul ve AMS türünü değiştiremiyor." msgid "Please unload all filament before switching." -msgstr "Lütfen değiştirmeden önce tüm filamanı boşaltın." +msgstr "Lütfen değiştirmeden önce tüm filamenti boşaltın." msgid "AMS type switching needs firmware update, taking about 30s. Switch now?" msgstr "AMS tipi anahtarlama, yaklaşık 30 saniye süren ürün yazılımı güncellemesi gerektirir. Şimdi değiştirilsin mi?" @@ -4594,7 +4594,7 @@ msgid "Failed to install the plug-in. The plug-in file may be in use. Please res msgstr "Eklenti yüklenemedi. Eklenti dosyası kullanımda olabilir. Lütfen OrcaSlicer'ı yeniden başlatın ve tekrar deneyin. Ayrıca anti-virüs yazılımı tarafından engellenip engellenmediğini veya silinip silinmediğini de kontrol edin." msgid "Click here to see more info" -msgstr "daha fazla bilgi görmek için burayı tıklayın" +msgstr "Daha fazla bilgi görmek için buraya tıklayın" msgid "The network plug-in was installed but could not be loaded. Please restart the application." msgstr "Ağ eklentisi kuruldu ancak yüklenemedi. Lütfen uygulamayı yeniden başlatın." @@ -4612,7 +4612,7 @@ msgid "Go Home" msgstr "Anasayfaya Git" msgid "An error occurred. The system may have run out of memory, or a bug may have occurred." -msgstr "Bir hata oluştu. Belki sistemin hafızası yeterli değildir veya programın bir hatasıdır" +msgstr "Bir hata oluştu. Sistem belleği tükenmiş veya bir yazılım hatası meydana gelmiş olabilir." #, boost-format msgid "A fatal error occurred: \"%1%\"" @@ -4622,7 +4622,7 @@ msgid "Please save your project and restart the application." msgstr "Lütfen projeyi kaydedin ve programı yeniden başlatın." msgid "Processing G-Code from previous file…" -msgstr "Önceki dosyadan G Kodu işleniyor..." +msgstr "Önceki dosyadan G-Kodu işleniyor…" msgid "Slicing complete" msgstr "Dilimleme tamamlandı" @@ -4686,7 +4686,7 @@ msgid "G-code file exported to %1%" msgstr "G kodu dosyası %1%’e aktarıldı" msgid "Unknown error with G-code export" -msgstr "G kodunu dışa aktarırken bilinmeyen hata." +msgstr "G-code dışa aktarımında bilinmeyen hata" #, boost-format msgid "" @@ -4699,7 +4699,7 @@ msgstr "" "Kaynak dosya %2%." msgid "Copying of the temporary G-code to the output G-code failed." -msgstr "Geçici G kodunun çıkış G koduna kopyalanması başarısız oldu" +msgstr "Geçici G-kodu dosyasının çıktı G-kodu dosyasına kopyalanması başarısız oldu." #, boost-format msgid "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue" @@ -4801,7 +4801,7 @@ msgid "" "Value was reset to 0.5" msgstr "" "Maksimum hacimsel hız çok küçük.\n" -"0,5'e sıfırla." +"Değer 0.5 olarak sıfırlandı" #, c-format, boost-format msgid "Current chamber temperature is higher than the material's safe temperature; this may result in material softening and nozzle clogs. The maximum safe temperature for the material is %d" @@ -4816,24 +4816,24 @@ msgid "" "Layer height too small\n" "It has been reset to 0.2" msgstr "" -"Katman yüksekliği çok küçük.\n" -"0,2'ye sıfırla." +"Katman yüksekliği çok küçük\n" +"Değer 0.2 olarak yeniden ayarlandı" msgid "" "Ironing spacing too small\n" "It has been reset to 0.1" msgstr "" -"Çok küçük ütüleme aralığı.\n" -"0,1'e sıfırla." +"Ütüleme satır aralığı çok küçük\n" +"Değer 0.1 olarak yeniden ayarlandı" msgid "" "Zero initial layer height is invalid.\n" "\n" "The first layer height will be reset to 0.2." msgstr "" -"Sıfır başlangıç katman yüksekliği geçersiz.\n" +"İlk katman yüksekliği sıfır olamaz.\n" "\n" -"İlk katman yüksekliği 0.2 olarak sıfırlanacak." +"İlk katman yüksekliği 0.2 olarak sıfırlandı." # AI Translated msgid "" @@ -4909,8 +4909,8 @@ msgid "" "seam_slope_start_height need to be smaller than layer_height.\n" "Reset to 0." msgstr "" -"Dikiş eğimi başlangıç yüksekliğinin katman yüksekliğinden daha küçük olması gerekir.\n" -"0 a sıfırla." +"seam_slope_start_height, layer_height değerinden küçük olmalıdır.\n" +"Değeri 0 yapın." #, no-c-format, no-boost-format msgid "" @@ -4969,7 +4969,7 @@ msgid "Paused (filament ran out)" msgstr "Duraklatıldı (filament bitti)" msgid "Heating nozzle" -msgstr "Isıtma memesi" +msgstr "Isıtma nozulü" msgid "Calibrating dynamic flow" msgstr "Dinamik akışı kalibre etme" @@ -5065,7 +5065,7 @@ msgid "Measure motion accuracy" msgstr "Hareket doğruluğunu ölçün" msgid "Nozzle offset calibration" -msgstr "Meme ofset kalibrasyonu" +msgstr "Nozul ofset kalibrasyonu" msgid "High temperature auto bed leveling" msgstr "Yüksek sıcaklıkta otomatik yatak tesviyesi" @@ -5122,7 +5122,7 @@ msgid "Measuring Surface" msgstr "Ölçüm Yüzeyi" msgid "Calibrating the detection position of nozzle clumping" -msgstr "Meme topaklanmasının algılama konumunu kalibre etme" +msgstr "Nozul topaklanmasının algılama konumunu kalibre etme" msgid "Update successful." msgstr "Güncelleme başarılı." @@ -5153,17 +5153,17 @@ msgstr "Güvenliğinizi sağlamak için belirli işleme görevleri (lazer gibi) #, c-format, boost-format msgid "The chamber temperature is too high, which may cause the filament to soften. Please wait until the chamber temperature drops below %d℃. You may open the front door or enable fans to cool down." -msgstr "Oda sıcaklığı çok yüksek, bu da filamanın yumuşamasına neden olabilir. Lütfen hazne sıcaklığı %d°C'nin altına düşene kadar bekleyin. Ön kapıyı açabilir veya fanların soğumasını sağlayabilirsiniz." +msgstr "Oda sıcaklığı çok yüksek, bu da filamentin yumuşamasına neden olabilir. Lütfen hazne sıcaklığı %d°C'nin altına düşene kadar bekleyin. Ön kapıyı açabilir veya fanların soğumasını sağlayabilirsiniz." #, c-format, boost-format msgid "AMS temperature is too high, which may cause the filament to soften. Please wait until the AMS temperature drops below %d℃." -msgstr "AMS sıcaklığı çok yüksek, bu da filamanın yumuşamasına neden olabilir. Lütfen AMS sıcaklığı %d°C'nin altına düşene kadar bekleyin." +msgstr "AMS sıcaklığı çok yüksek, bu da filamentin yumuşamasına neden olabilir. Lütfen AMS sıcaklığı %d°C'nin altına düşene kadar bekleyin." msgid "The current chamber temperature or the target chamber temperature exceeds 45℃. In order to avoid extruder clogging, low temperature filament(PLA/PETG/TPU) is not allowed to be loaded." msgstr "Mevcut hazne sıcaklığı veya hedef hazne sıcaklığı 45°C'yi aşıyor. Ekstruderin tıkanmasını önlemek için düşük sıcaklık filamentinin (PLA/PETG/TPU) yüklenmesine izin verilmez." msgid "Low temperature filament(PLA/PETG/TPU) is loaded in the extruder. In order to avoid extruder clogging, it is not allowed to set the chamber temperature." -msgstr "Ekstrudere düşük sıcaklık filamanı (PLA/PETG/TPU) yüklenir. Ekstruderin tıkanmasını önlemek için hazne sıcaklığının ayarlanmasına izin verilmez." +msgstr "Ekstrudere düşük sıcaklık filamenti (PLA/PETG/TPU) yüklenir. Ekstruderin tıkanmasını önlemek için hazne sıcaklığının ayarlanmasına izin verilmez." msgid "When you set the chamber temperature below 40℃, the chamber temperature control will not be activated, and the target chamber temperature will automatically be set to 0℃." msgstr "Hazne sıcaklığını 40°C'nin altına ayarladığınızda, hazne sıcaklık kontrolü etkinleştirilmeyecektir. Ve hedef hazne sıcaklığı otomatik olarak 0°C'ye ayarlanacaktır." @@ -5477,7 +5477,7 @@ msgid "Noop" msgstr "Hayır" msgid "Retract" -msgstr "Geri çekme" +msgstr "Geri Çekme" msgid "Unretract" msgstr "İleri İtme" @@ -5568,10 +5568,10 @@ msgid "Layer Time: " msgstr "Katman Süresi: " msgid "Tool: " -msgstr "Alet:" +msgstr "Kafa: " msgid "Color: " -msgstr "Renk:" +msgstr "Renk: " # AI Translated msgid "Acceleration: " @@ -5581,7 +5581,7 @@ msgid "Jerk: " msgstr "Jerk: " msgid "PA: " -msgstr "PA:" +msgstr "PA: " msgid "mm/s" msgstr "mm/s" @@ -5780,7 +5780,7 @@ msgid "" "Please ensure the filaments used by this object are not arranged to other nozzles." msgstr "" "Yalnızca sol/sağ püskürtme ucu alanına bir nesne yerleştirilmiş veya sol püskürtme ucunun yazdırılabilir yüksekliğini aşıyor.\n" -"Lütfen bu nesne tarafından kullanılan filamanların diğer püskürtme uçlarına göre düzenlenmediğinden emin olun." +"Lütfen bu nesne tarafından kullanılan filamentlerin diğer püskürtme uçlarına göre düzenlenmediğinden emin olun." msgid "" "An object is laid over the boundary of plate or exceeds the height limit.\n" @@ -5852,7 +5852,7 @@ msgid "The position or size of the model %s exceeds the %s's printable range." msgstr "%s modelinin konumu veya boyutu %s'nin yazdırılabilir aralığını aşıyor." msgid " Please check and adjust the part's position or size to fit the printable range:\n" -msgstr "Lütfen parçanın konumunu veya boyutunu kontrol edip yazdırılabilir aralığa uyacak şekilde ayarlayın:\n" +msgstr " Lütfen parçanın konumunu veya boyutunu basılabilir alana sığacak şekilde kontrol edip ayarlayın:\n" #, boost-format msgid "Left nozzle: X:%1%-%2%, Y:%3%-%4%, Z:%5%-%6%\n" @@ -5958,7 +5958,7 @@ msgid "Select Plate" msgstr "Plaka Seç" msgid "Slicing" -msgstr "Dilimleniyor" +msgstr "Dilimleme" msgid "Slice all" msgstr "Hepsini dilimle" @@ -6072,19 +6072,19 @@ msgstr "Araç %d" #, c-format, boost-format msgid "Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s." -msgstr "%s filamanı %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." +msgstr "%s filamenti %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." #, c-format, boost-format msgid "Filaments %s are placed in the %s, but the generated G-code path exceeds the printable range of the %s." -msgstr "%s filamanları %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." +msgstr "%s filamentleri %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." #, c-format, boost-format msgid "Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s." -msgstr "%s filamanı %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." +msgstr "%s filamenti %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." #, c-format, boost-format msgid "Filaments %s are placed in the %s, but the generated G-code path exceeds the printable height of the %s." -msgstr "%s filamanları %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." +msgstr "%s filamentleri %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." msgid "Open wiki for more information." msgstr "Daha fazla bilgi için wiki'yi açın." @@ -6200,7 +6200,7 @@ msgstr "" "şekilde gösterildiği gibi yazıcıda:" msgid "Invalid input" -msgstr "Geçersiz Giriş." +msgstr "Geçersiz değer" msgid "New Window" msgstr "Yeni Pencere" @@ -6581,7 +6581,7 @@ msgid "Flow Rate Calibration" msgstr "Akış Hızı Kalibrasyonu" msgid "Retraction" -msgstr "Geri Çekme" +msgstr "Geri çekme" msgid "Cornering" msgstr "Köşe dönüşü" @@ -7193,7 +7193,7 @@ msgid "When printing is paused, filament loading and unloading are only supporte msgstr "Yazdırma duraklatıldığında filament yükleme ve boşaltma yalnızca harici yuvalar için desteklenir." msgid "Current extruder is busy changing filament." -msgstr "Mevcut ekstruder filamanı değiştirmekle meşgul." +msgstr "Mevcut ekstruder filamenti değiştirmekle meşgul." # AI Translated msgid "\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch." @@ -7336,7 +7336,7 @@ msgid "Upload failed\n" msgstr "Yükleme başarısız\n" msgid "Obtaining instance_id failed\n" -msgstr "instance_id alınamadı\n" +msgstr "Örnek kimliği (instance_id) alınamadı\n" msgid "" "Your comment result cannot be uploaded due to the following reasons:\n" @@ -7505,13 +7505,13 @@ msgid "Undo integration failed." msgstr "Entegrasyon geri alınamadı." msgid "Exporting" -msgstr "Dışa Aktarılıyor." +msgstr "Dışa aktarılıyor" msgid "An update is available!" -msgstr "Yazılımın Yeni sürümü var." +msgstr "Yeni bir güncelleme mevcut!" msgid "Go to download page" -msgstr "İndirme sayfasına gidin." +msgstr "İndirme sayfasına git" msgid "Open Folder." msgstr "Klasörü Aç." @@ -7726,10 +7726,10 @@ msgid "Nozzle Clumping Detection" msgstr "Nozul Topaklanma Algılaması" msgid "Check if the nozzle is clumping by filaments or other foreign objects." -msgstr "Memenin filamanlar veya diğer yabancı nesneler tarafından topaklanıp topaklanmadığını kontrol edin." +msgstr "Nozulun filamentler veya diğer yabancı nesneler tarafından topaklanıp topaklanmadığını kontrol edin." msgid "Detects air printing caused by nozzle clogging or filament grinding." -msgstr "Nozul tıkanması veya filaman taşlamasından kaynaklanan hava baskısını algılar." +msgstr "Nozul tıkanması veya filament taşlamasından kaynaklanan hava baskısını algılar." msgid "First Layer Inspection" msgstr "Birinci Katman Denetimi" @@ -7901,14 +7901,14 @@ msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Yazdırmada %1% ile %2%'nin karıştırılması önerilmez.\n" msgid " nozzle" -msgstr "meme" +msgstr " nozul" #, boost-format msgid "It is not recommended to print the following filament(s) with %1%: %2%\n" msgstr "Aşağıdaki filament(ler)in %1%: %2% ile yazdırılması önerilmez.\n" msgid "It is not recommended to use the following nozzle and filament combinations:\n" -msgstr "Aşağıdaki nozul ve filaman kombinasyonlarının kullanılması tavsiye edilmez:\n" +msgstr "Aşağıdaki nozul ve filament kombinasyonlarının kullanılması tavsiye edilmez:\n" #, boost-format msgid "%1% with %2%\n" @@ -7982,7 +7982,7 @@ msgstr "" "Senkronizasyona devam edeceğinizden emin misiniz?" msgid "There are unset nozzle types. Please set the nozzle types of all extruders before synchronizing." -msgstr "Ayarlanmamış nozul tipleri vardır. Lütfen senkronizasyondan önce tüm ekstrüderlerin nozül tiplerini ayarlayın." +msgstr "Ayarlanmamış nozul tipleri vardır. Lütfen senkronizasyondan önce tüm ekstrüderlerin nozul tiplerini ayarlayın." msgid "Sync extruder infomation" msgstr "Ekstruder bilgilerini senkronize et" @@ -8045,7 +8045,7 @@ msgstr "" "Sistem ön ayarlarında bir güncelleme olup olmadığını kontrol etmek için lütfen Orca Slicer'ı güncelleyin veya Orca Slicer'ı yeniden başlatın." msgid "Only filament color information has been synchronized from printer." -msgstr "Yazıcıdan yalnızca filaman renk bilgisi senkronize edildi." +msgstr "Yazıcıdan yalnızca filament renk bilgisi senkronize edildi." msgid "Filament type and color information have been synchronized, but slot information is not included." msgstr "Filament türü ve renk bilgisi senkronize edilmiştir ancak slot bilgisi dahil edilmemiştir." @@ -8249,7 +8249,7 @@ msgid "Export AMF file:" msgstr "AMF dosyasını dışa aktar:" msgid "Save file as" -msgstr "Farklı kaydet:" +msgstr "Dosyayı farklı kaydet" msgid "Export OBJ file:" msgstr "OBJ dosyasını dışa aktar:" @@ -8420,7 +8420,7 @@ msgid "" "Would you like to sync now?" msgstr "" "Püskürtme ucu türü ve AMS miktarı bilgileri bağlı yazıcıdan senkronize edilmedi.\n" -"Senkronizasyondan sonra yazılım, dilimleme sırasında baskı süresini ve filaman kullanımını optimize edebilir.\n" +"Senkronizasyondan sonra yazılım, dilimleme sırasında baskı süresini ve filament kullanımını optimize edebilir.\n" "Şimdi senkronize etmek ister misiniz?" msgid "Sync now" @@ -8455,7 +8455,7 @@ msgid "Download failed; unknown file format." msgstr "İndirme başarısız oldu, dosya türü bilinmiyor." msgid "Downloading project..." -msgstr "proje indiriliyor..." +msgstr "Proje indiriliyor..." msgid "Download failed; File size exception." msgstr "İndirme başarısız oldu, Dosya boyutu sorunlu." @@ -8483,10 +8483,10 @@ msgid "The selected file" msgstr "Seçili dosya" msgid "Does not contain valid G-code." -msgstr "geçerli gcode içermiyor." +msgstr "Geçerli bir G-kodu içermiyor." msgid "An Error has occurred while loading the G-code file." -msgstr "G kodu dosyası yüklenirken hata oluşuyor" +msgstr "G-code dosyası yüklenirken bir hata oluştu." #. TRN %1% is archive path #, boost-format @@ -8524,7 +8524,7 @@ msgid "G-code files and models cannot be loaded together!" msgstr "G kodu dosyaları modellerle birlikte yüklenemez!" msgid "Unable to add models in preview mode" -msgstr "Önizleme modundayken model eklenemiyor!" +msgstr "Önizleme modundayken model ekleyemezsiniz" msgid "All objects will be removed, continue?" msgstr "Tüm nesneler kaldırılacak, devam edilsin mi?" @@ -8558,7 +8558,7 @@ msgid "The file %s has been sent to the printer's storage space and can be viewe msgstr "%s dosyası yazıcının depolama alanına gönderildi ve yazıcıda görüntülenebiliyor." msgid "The nozzle type is not set. Please set the nozzle and try again." -msgstr "Nozül tipi ayarlanmamış. Lütfen memeyi ayarlayın ve tekrar deneyin." +msgstr "Nozul tipi ayarlanmamış. Lütfen nozulu ayarlayın ve tekrar deneyin." msgid "The nozzle type is not set. Please check." msgstr "Nozül tipi ayarlanmamış. Lütfen kontrol edin." @@ -8813,7 +8813,7 @@ msgid "" msgstr "" "Önemli ölçüde farklı sıcaklıklara sahip filamentlerin kullanılması aşağıdakilere neden olabilir:\n" "• Ekstruder tıkanması\n" -"• Meme hasarı\n" +"• Nozul hasarı\n" "• Katman yapışma sorunları\n" "\n" "Bu özelliği etkinleştirmeye devam etmek istiyor musunuz?" @@ -8863,7 +8863,7 @@ msgid "Associate" msgstr "Ortak" msgid "with OrcaSlicer so that Orca can open models from" -msgstr "Orca’nın modelleri açabilmesi için OrcaSlicer ile" +msgstr "orca'nın modelleri şuradan açabilmesi için OrcaSlicer ile (ilişkilendir / eşleştir)" msgid "Current Association: " msgstr "Mevcut Bağlantı: " @@ -8899,7 +8899,7 @@ msgid "Enable dark Mode" msgstr "Karanlık modu etkinleştir" msgid "Allow only one OrcaSlicer instance" -msgstr "Yalnızca bir OrcaSlicer örneğine izin ver" +msgstr "Yalnızca bir orca slicer örneğine izin ver" msgid "On OSX there is always only one instance of app running by default. However it is allowed to run multiple instances of same app from the command line. In such case this settings will allow only one instance." msgstr "OSX’te her zaman varsayılan olarak çalışan tek bir uygulama örneği vardır. Ancak aynı uygulamanın birden fazla örneğinin komut satırından çalıştırılmasına izin verilir. Böyle bir durumda bu ayarlar yalnızca bir örneğe izin verecektir." @@ -9038,7 +9038,7 @@ msgid "If enabled, saved projects store the absolute path to imported source fil msgstr "Etkinleştirildiğinde kaydedilen projeler, içe aktarılan kaynak dosyaların (STEP/STL/...) mutlak yolunu saklar; böylece kaynak dosya projeden farklı bir klasörde tutulsa bile \"Diskten yeniden yükle\" çalışmayı sürdürür. Devre dışı bırakıldığında yalnızca dosya adı saklanır; bu da projeleri taşınabilir tutar ve mutlak yolların gömülmesini önler." msgid "Preset" -msgstr "Ön ayar" +msgstr "Ön Ayar" msgid "Remember printer configuration" msgstr "Yazıcı yapılandırmasını hatırla" @@ -9065,7 +9065,7 @@ msgid "filaments" msgstr "filamentler" msgid "Optimizes filament area maximum height by chosen filament count." -msgstr "Seçilen filaman sayısına göre filaman alanı maksimum yüksekliğini optimize eder." +msgstr "Seçilen filament sayısına göre filament alanı maksimum yüksekliğini optimize eder." # AI Translated msgid "Show shared profiles notification" @@ -9079,7 +9079,7 @@ msgid "Features" msgstr "Özellikler" msgid "Multi device management" -msgstr "Çoklu Cihaz Yönetimi" +msgstr "Çoklu cihaz yönetimi" msgid "With this option enabled, you can send a task to multiple devices at the same time and manage multiple devices." msgstr "Bu seçenek etkinleştirildiğinde, aynı anda birden fazla cihaza bir görev gönderebilir ve birden fazla cihazı yönetebilirsiniz." @@ -9159,7 +9159,7 @@ msgstr "Kaydır" # AI Translated msgid "Left Mouse Drag" -msgstr "Sol Fare Sürükleme" +msgstr "Sol fare sürükleme" # AI Translated msgid "Set the action that dragging the left mouse button should perform." @@ -9167,7 +9167,7 @@ msgstr "Sol fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarlay # AI Translated msgid "Middle Mouse Drag" -msgstr "Orta Fare Sürükleme" +msgstr "Orta fare sürükleme" # AI Translated msgid "Set the action that dragging the middle mouse button should perform." @@ -9175,14 +9175,14 @@ msgstr "Orta fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarla # AI Translated msgid "Right Mouse Drag" -msgstr "Sağ Fare Sürükleme" +msgstr "Sağ fare sürükleme" # AI Translated msgid "Set the action that dragging the right mouse button should perform." msgstr "Sağ fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarlayın." msgid "Clear my choice on..." -msgstr "Seçimimi temizle..." +msgstr "Seçimimi Temizle" msgid "Unsaved projects" msgstr "Kaydedilmemiş projeler" @@ -9245,7 +9245,7 @@ msgid "Renders cast shadows on the plate, other objects, and each object onto it msgstr "Gerçekçi görünümde plakaya, diğer nesnelere ve her nesnenin kendi üzerine düşen gölgeleri işler." msgid "Anti-aliasing" -msgstr "Anti-aliasing" +msgstr "Anti-Aliasing" # AI Translated msgid "MSAA Multiplier" @@ -9382,7 +9382,7 @@ msgid "Allow logging into Bambu Cloud alongside Orca Cloud. When enabled, a Bamb msgstr "Orca Cloud'un yanı sıra Bambu Cloud'a giriş yapılmasına izin verir. Etkinleştirildiğinde ana sayfada bir Bambu giriş bölümü görünür." msgid "Update & sync" -msgstr "Güncelle ve senkronize et" +msgstr "Güncelle ve Senkronize Et" msgid "Check for stable updates only" msgstr "Yalnızca kararlı güncellemeleri kontrol edin" @@ -9394,7 +9394,7 @@ msgid "Filament sync mode" msgstr "Filament senkronizasyon modu" msgid "Choose whether sync updates both filament preset and color, or only color." -msgstr "Senkronizasyonun hem filaman ön ayarını hem de rengini mi, yoksa yalnızca rengi mi güncelleyeceğini seçin." +msgstr "Senkronizasyonun hem filament ön ayarını hem de rengini mi, yoksa yalnızca rengi mi güncelleyeceğini seçin." msgid "Filament & Color" msgstr "Filament ve Renk" @@ -9403,7 +9403,7 @@ msgid "Color only" msgstr "Yalnızca renk" msgid "Update built-in presets automatically." -msgstr "Yerleşik Ön Ayarları otomatik olarak güncelleyin." +msgstr "Yerleşik ön ayarları otomatik olarak güncelleyin." msgid "Use encrypted file for token storage" msgstr "Belirteç depolaması için şifrelenmiş dosyayı kullan" @@ -9413,7 +9413,7 @@ msgstr "Kimlik doğrulama belirteçlerini sistem anahtarlığı yerine şifrelen # AI Translated msgid "Bambu network plug-in" -msgstr "Bambu ağ eklentisi" +msgstr "Bambu Ağ Eklentisi" # AI Translated msgid "Enable Bambu network plug-in" @@ -9440,7 +9440,7 @@ msgid "Associate 3MF files to OrcaSlicer" msgstr ".3mf dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open 3MF files." -msgstr "Etkinleştirilirse, OrcaSlicer'ı .3mf dosyalarını açacak varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, 3MF dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate DRC files to OrcaSlicer" msgstr "DRC dosyalarını OrcaSlicer ile ilişkilendirin" @@ -9452,13 +9452,13 @@ msgid "Associate STL files to OrcaSlicer" msgstr ".stl dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open STL files." -msgstr "Etkinleştirilirse OrcaSlicer'ı .stl dosyalarını açmak için varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, STL dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate STEP files to OrcaSlicer" msgstr ".step/.stp dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open STEP files." -msgstr "Etkinleştirilirse, OrcaSlicer'ı .step dosyalarını açmak için varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, STEP dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate web links to OrcaSlicer" msgstr "Web bağlantılarını OrcaSlicer ile ilişkilendirin" @@ -9561,10 +9561,10 @@ msgid "Product host" msgstr "Ürün ana bilgisayarı" msgid "Debug save button" -msgstr "hata ayıklama kaydet düğmesi" +msgstr "Hata ayıklama kaydetme butonu" msgid "Save debug settings" -msgstr "hata ayıklama ayarlarını kaydet" +msgstr "Hata ayıklama ayarlarını kaydet" msgid "Debug settings have been saved successfully!" msgstr "DEBUG ayarları başarıyla kaydedildi!" @@ -9612,7 +9612,7 @@ msgid "Change extruder color" msgstr "Ekstruder rengini değiştir" msgid "Unspecified" -msgstr "belirtilmemiş" +msgstr "Tanımlanmamış" msgid "Project-inside presets" msgstr "Proje içi ön ayarlar" @@ -9799,22 +9799,22 @@ msgstr "Görev iptal edildi" # AI Translated msgid "Bambu Cool Plate" -msgstr "Bambu Soğuk Plaka" +msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA Plaka" msgid "Bambu Engineering Plate" -msgstr "Bambu Mühendislik Plakası" +msgstr "Bambu Engineering Plate" msgid "Bambu Smooth PEI Plate" -msgstr "Bambu Pürüzsüz PEI Plaka" - -msgid "High temperature Plate" msgstr "Bambu Smooth PEI Plate" +msgid "High temperature Plate" +msgstr "High temperature Plate" + msgid "Bambu Textured PEI Plate" -msgstr "Bambu Dokulu PEI Plaka" +msgstr "Bambu Textured PEI Plate" msgid "Bambu Cool Plate SuperTack" msgstr "Bambu Cool Plate SuperTack" @@ -9832,7 +9832,7 @@ msgid "Multi-color with external" msgstr "Çok renkli harici" msgid "Your filament grouping method in the sliced file is not optimal." -msgstr "Dilimlenmiş dosyadaki filaman gruplama yönteminiz optimal değil." +msgstr "Dilimlenmiş dosyadaki filament gruplama yönteminiz optimal değil." # AI Translated msgid "To ensure print quality, the drying temperature will be lowered during printing." @@ -9881,7 +9881,7 @@ msgid "Nozzles and filaments of the same type share the same PA profile." msgstr "Aynı tipteki nozullar ve filamentler aynı PA profilini paylaşır." msgid "Send complete" -msgstr "gönderme tamamlandı" +msgstr "Gönderme tamamlandı" msgid "Error code" msgstr "Hata kodu" @@ -9962,10 +9962,10 @@ msgid "Errors" msgstr "Hatalar" msgid "More than one filament types have been mapped to the same external spool, which may cause printing issues. The printer won't pause during printing." -msgstr "Aynı harici makaraya birden fazla filaman türü eşlenmiştir; bu durum, yazdırma sorunlarına neden olabilir. Yazıcı yazdırma sırasında duraklamaz." +msgstr "Aynı harici makaraya birden fazla filament türü eşlenmiştir; bu durum, yazdırma sorunlarına neden olabilir. Yazıcı yazdırma sırasında duraklamaz." msgid "The filament type setting of external spool is different from the filament in the slicing file." -msgstr "Harici makaranın filaman türü ayarı, dilimleme dosyasındaki filamandan farklıdır." +msgstr "Harici makaranın filament türü ayarı, dilimleme dosyasındaki filamentden farklıdır." msgid "The printer type selected when generating G-code is not consistent with the currently selected printer. It is recommended that you use the same printer type for slicing." msgstr "G Kodu oluşturulurken seçilen yazıcı türü mevcut seçili yazıcıyla tutarlı değil. Dilimleme için aynı yazıcı tipini kullanmanız tavsiye edilir." @@ -10039,7 +10039,7 @@ msgid "Cost %dg filament and %d changes more than optimal grouping." msgstr "Maliyet %dg filament ve %d, optimum gruplandırmadan daha fazla değişir." msgid "nozzle" -msgstr "meme" +msgstr "nozul" # AI Translated #, c-format, boost-format @@ -10092,7 +10092,7 @@ msgstr "Geçerli yazıcının %s çapı(%.1fmm) dilimleme dosyasıyla (%.1fmm) e #, c-format, boost-format msgid "The current nozzle diameter (%.1fmm) doesn't match with the slicing file (%.1fmm). Please make sure the nozzle installed matches with settings in printer, then set the corresponding printer preset when slicing." -msgstr "Mevcut nozül çapı (%.1fmm) dilimleme dosyasıyla (%.1fmm) eşleşmiyor. Lütfen takılan püskürtme ucunun yazıcıdaki ayarlarla eşleştiğinden emin olun, ardından dilimleme sırasında ilgili yazıcı ön ayarını yapın." +msgstr "Mevcut nozul çapı (%.1fmm) dilimleme dosyasıyla (%.1fmm) eşleşmiyor. Lütfen takılan püskürtme ucunun yazıcıdaki ayarlarla eşleştiğinden emin olun, ardından dilimleme sırasında ilgili yazıcı ön ayarını yapın." msgid "both extruders" msgstr "her iki ekstruder" @@ -10132,33 +10132,33 @@ msgstr "[ %s ] yüksek sıcaklıktaki bir ortamda yazdırmayı gerektirir." #, c-format, boost-format msgid "The filament on %s may soften. Please unload." -msgstr "%s üzerindeki filaman yumuşayabilir. Lütfen boşaltın." +msgstr "%s üzerindeki filament yumuşayabilir. Lütfen boşaltın." #, c-format, boost-format msgid "The filament on %s is unknown and may soften. Please set filament." -msgstr "%s üzerindeki filaman bilinmiyor ve yumuşayabilir. Lütfen filamenti ayarlayın." +msgstr "%s üzerindeki filament bilinmiyor ve yumuşayabilir. Lütfen filamenti ayarlayın." msgid "Unable to automatically match to suitable filament. Please click to manually match." -msgstr "Uygun filamanla otomatik olarak eşleştirilemiyor. Manuel olarak eşleştirmek için lütfen tıklayın." +msgstr "Uygun filamentle otomatik olarak eşleştirilemiyor. Manuel olarak eşleştirmek için lütfen tıklayın." msgid "Install toolhead enhanced cooling fan to prevent filament softening." msgstr "Filament yumuşamasını önlemek için takım başlığı geliştirilmiş soğutma fanını takın." # AI Translated msgid "Smooth Cool Plate" -msgstr "Pürüzsüz Soğuk Plaka" +msgstr "Smooth Cool Plate" # AI Translated msgid "Engineering Plate" -msgstr "Mühendislik Plakası" +msgstr "Engineering Plate" # AI Translated msgid "Smooth High Temp Plate" -msgstr "Pürüzsüz Yüksek Sıcaklık Plakası" +msgstr "Smooth High Temp Plate" # AI Translated msgid "Textured PEI Plate" -msgstr "Dokulu PEI Plaka" +msgstr "Textured PEI Plate" msgid "Cool Plate (SuperTack)" msgstr "Cool Plate (SuperTack)" @@ -10167,25 +10167,25 @@ msgid "Click here if you can't connect to the printer" msgstr "Yazıcıya bağlanamıyorsanız burayı tıklayın" msgid "No login account, only printers in LAN mode are displayed." -msgstr "Oturum açma hesabı yok, yalnızca LAN modundaki yazıcılar görüntüleniyor" +msgstr "Oturum açılmadı; yalnızca LAN modundaki yazıcılar görüntüleniyor." msgid "Connecting to server..." -msgstr "Sunucuya baglanıyor" +msgstr "Sunucuya bağlanılıyor..." msgid "Synchronizing device information..." -msgstr "Cihaz bilgileri senkronize ediliyor" +msgstr "Cihaz bilgileri senkronize ediliyor..." msgid "Synchronizing device information timed out." -msgstr "Cihaz bilgilerinin senkronize edilmesi zaman aşımı" +msgstr "Cihaz bilgileri senkronizasyonu zaman aşımına uğradı." msgid "Cannot send a print job when the printer is not at FDM mode." msgstr "Yazıcı FDM modunda değilken yazdırma işi gönderilemiyor." msgid "Cannot send a print job while the printer is updating firmware." -msgstr "Yazıcı ürün yazılımını güncellerken yazdırma işi gönderilemiyor" +msgstr "Yazıcı yazılımı güncellenirken yeni bir baskı başlatılamaz." msgid "The printer is executing instructions. Please restart printing after it ends." -msgstr "Yazıcı talimatları yürütüyor. Lütfen bittikten sonra yazdırmayı yeniden başlatın" +msgstr "Yazıcı komutları yürütüyor. Lütfen işlem bittikten sonra baskıyı tekrar başlatın." msgid "AMS is setting up. Please try again later." msgstr "AMS kuruluyor. Lütfen daha sonra tekrar deneyin." @@ -10212,7 +10212,7 @@ msgid "Cannot send the print job to a printer whose firmware must be updated." msgstr "Yazdırma işi, ürün yazılımının güncellenmesi gereken bir yazıcıya gönderilemiyor." msgid "Cannot send a print job for an empty plate." -msgstr "Boş kalıp için yazdırma işi gönderilemiyor" +msgstr "Boş bir tabla için baskı işi gönderilemez." msgid "Storage needs to be inserted to record timelapse." msgstr "Hızlandırılmış çekimi kaydetmek için depolama biriminin eklenmesi gerekir." @@ -10227,7 +10227,7 @@ msgid "Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value msgstr "Özel dinamik akış değerini etkinleştirmek için dinamik akış kalibrasyonunu 'KAPALI' olarak ayarlayın." msgid "This printer does not support printing all plates." -msgstr "Bu yazıcı tüm kalıpların yazdırılmasını desteklemiyor" +msgstr "Bu yazıcı tüm plakaların bastırılmasını desteklemiyor." # AI Translated #, c-format, boost-format @@ -10296,7 +10296,7 @@ msgid "Sending failed, please try again!" msgstr "Gönderme başarısız oldu, lütfen yeniden deneyin!" msgid "Slice complete" -msgstr "Dilimleme tamam." +msgstr "Dilimleme tamamlandı" msgid "View all Daily tips" msgstr "Tüm Günlük ipuçlarını görüntüleyin" @@ -10475,8 +10475,8 @@ msgid "" "No - Do not change these settings for me." msgstr "" "Bu ayarlar otomatik olarak değiştirilsin mi?\n" -"Evet - Bu ayarları otomatik olarak değiştir\n" -"Hayır - Bu ayarları benim için değiştirme" +"Evet - Ayarları otomatik olarak uygula.\n" +"Hayır - Ayarları değiştirme." msgid "" "When using soluble material for the support interface, we recommend the following settings:\n" @@ -10513,10 +10513,10 @@ msgid "Adjust" msgstr "Ayarla" msgid "Experimental feature: Retracting and cutting off the filament at a greater distance during filament changes to minimize flush. Although it can notably reduce flush, it may also elevate the risk of nozzle clogs or other printing complications." -msgstr "Deneysel özellik: Filament değişiklikleri sırasında, floşu en aza indirmek için filamanı daha büyük bir mesafeden geri çekmek ve kesmek. Flush’u önemli ölçüde azaltabilmesine rağmen, aynı zamanda nozül tıkanmaları veya diğer yazdırma komplikasyonları riskini de artırabilir." +msgstr "Deneysel özellik: Filament değişiklikleri sırasında, floşu en aza indirmek için filamenti daha büyük bir mesafeden geri çekmek ve kesmek. Flush’u önemli ölçüde azaltabilmesine rağmen, aynı zamanda nozul tıkanmaları veya diğer yazdırma komplikasyonları riskini de artırabilir." msgid "Experimental feature: Retracting and cutting off the filament at a greater distance during filament changes to minimize flush. Although it can notably reduce flush, it may also elevate the risk of nozzle clogs or other printing complications. Please use with the latest printer firmware." -msgstr "Deneysel özellik: Filament değişiklikleri sırasında, filamanın en aza indirilmesi için filamanın daha büyük bir mesafeden geri çekilmesi ve kesilmesi. Akmayı önemli ölçüde azaltabilmesine rağmen, aynı zamanda püskürtme uçları tıkanması veya diğer yazdırma komplikasyonları riskini de artırabilir. Lütfen en son yazıcı ürün yazılımını kullanın." +msgstr "Deneysel özellik: Filament değişiklikleri sırasında, filamentin en aza indirilmesi için filamentin daha büyük bir mesafeden geri çekilmesi ve kesilmesi. Akmayı önemli ölçüde azaltabilmesine rağmen, aynı zamanda püskürtme uçları tıkanması veya diğer yazdırma komplikasyonları riskini de artırabilir. Lütfen en son yazıcı ürün yazılımını kullanın." msgid "" "When recording timelapse without toolhead, it is recommended to add a \"Timelapse Wipe Tower\" \n" @@ -10600,7 +10600,7 @@ msgstr "Hassasiyet" # AI Translated msgid "Z contouring" -msgstr "Z konturlama" +msgstr "Z Konturlama" msgid "Wall generator" msgstr "Duvar Türü" @@ -10619,7 +10619,7 @@ msgstr "Alt / Üst Katmanlar" # AI Translated msgid "First layer speed" -msgstr "İlk katman hızı" +msgstr "İlk Katman Hızı" msgid "Other layers speed" msgstr "Diğer Katmanlar" @@ -10653,7 +10653,7 @@ msgid "Support ironing" msgstr "Destek Ütüleme" msgid "Tree supports" -msgstr "Ağaç destekler" +msgstr "Ağaç Destekler" msgid "Multimaterial" msgstr "Çoklu Malzeme" @@ -10750,14 +10750,14 @@ msgid "Bed temperature when the Cool Plate SuperTack is installed. A value of 0 msgstr "Cool Plate SuperTack takılıyken yatak sıcaklığı. 0 değeri, filamentin Cool Plate SuperTack üzerine baskıyı desteklemediği anlamına gelir." msgid "Cool Plate" -msgstr "Soğuk plaka" +msgstr "Cool Plate" msgid "This is the bed temperature when the Cool Plate is installed. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Cool Plate takıldığında yatak sıcaklığı. 0 değeri, filamentin Cool Plate üzerine yazdırmayı desteklemediği anlamına gelir." # AI Translated msgid "Textured Cool Plate" -msgstr "Dokulu Soğuk Plaka" +msgstr "Textured Cool Plate" # AI Translated msgid "This is the bed temperature when the Textured Cool Plate is installed. A value of 0 means the filament does not support printing on the Textured Cool Plate." @@ -10768,7 +10768,7 @@ msgstr "Engineering Plate takıldığında yatak sıcaklığı. Değer 0, filame # AI Translated msgid "Smooth PEI Plate / High Temp Plate" -msgstr "Pürüzsüz PEI Plaka / Yüksek Sıcaklık Plakası" +msgstr "Smooth PEI Plate / High Temp Plate" msgid "This is the bed temperature when the Smooth PEI Plate/High Temperature Plate is installed. A value of 0 means the filament does not support printing on the Smooth PEI Plate/High Temp Plate." msgstr "Smooth PEI Plate / High Temp Plate takılığın da yatak sıcaklığı. 0 Değeri, filamentin Smooth PEI Plate / High Temp Plate üzerine baskı yapmayı desteklemediği anlamına gelir." @@ -10790,13 +10790,13 @@ msgstr "Minimum fan hızı" # AI Translated msgid "The part cooling fan will run at the minimum fan speed when the estimated layer time is longer than the threshold value. When the layer time is shorter than the threshold, the fan speed will be interpolated between the minimum and maximum fan speed according to layer printing time." -msgstr "Tahmini katman süresi eşik değerinden uzun olduğunda parça soğutma fanı minimum fan hızında çalışır. Katman süresi eşikten kısa olduğunda fan hızı, katman yazdırma süresine göre minimum ve maksimum fan hızı arasında enterpole edilir" +msgstr "Tahmini katman süresi eşik değerden uzun olduğunda parça soğutma fanı minimum fan hızında çalışır. Katman süresi eşik değerden kısa olduğunda fan hızı, katman baskı süresine göre minimum ve maksimum hızlar arasında kademeli olarak ayarlanır." msgid "Max fan speed threshold" msgstr "Maksimum fan hızı" msgid "The part cooling fan will run at maximum speed when the estimated layer time is shorter than the threshold value." -msgstr "Tahmini katman süresi ayar değerinden kısa olduğunda parça soğutma fanı hızı maksimum olacaktır" +msgstr "Tahmini katman süresi eşik değerden kısa olduğunda parça soğutma fanı maksimum hızda çalışır." msgid "Auxiliary part cooling fan" msgstr "Yardımcı parça soğutma fanı" @@ -11017,8 +11017,8 @@ msgstr "%1% Ön Ayar" msgid "The following preset will be deleted too:" msgid_plural "The following presets will be deleted too:" -msgstr[0] "Aşağıdaki ön ayar da silinecektir." -msgstr[1] "Aşağıdaki ön ayarlar da silinecektir." +msgstr[0] "Aşağıdaki önayar da silinecektir:" +msgstr[1] "Aşağıdaki önayarlar da silinecektir:" msgid "" "Are you sure to delete the selected preset?\n" @@ -11122,7 +11122,7 @@ msgid "Process Settings" msgstr "İşlem Ayarları" msgid "unsaved changes" -msgstr "Kaydedilmemiş Değişiklikler" +msgstr "kaydedilmemiş değişiklikler" msgid "Transfer or discard changes" msgstr "Değişiklikleri Çıkart veya Sakla" @@ -11187,7 +11187,7 @@ msgid "Click the right mouse button to display the full text." msgstr "Tam metni görüntülemek için farenin sağ tuşuna tıklayın." msgid "No changes will be saved." -msgstr "Tüm değişiklikler kaydedilmeyecek" +msgstr "Hiçbir değişiklik kaydedilmeyecek." msgid "All changes will be discarded." msgstr "Tüm değişiklikler iptal edilecek." @@ -11403,7 +11403,7 @@ msgid "view" msgstr "görüş" msgid "Current filament colors" -msgstr "Mevcut filaman renkleri" +msgstr "Mevcut filament renkleri" msgid "Matching" msgstr "Eşleştirme" @@ -11433,8 +11433,8 @@ msgid "" "The color has been selected, you can choose OK \n" " to continue or manually adjust it." msgstr "" -"Renk seçildi, Tamam'ı seçebilirsiniz \n" -" Devam etmek veya manuel olarak ayarlamak için" +"Renk seçildi; devam etmek için Tamam'ı seçebilir\n" +"veya elle ayarlayabilirsiniz." msgid "—> " msgstr "—> " @@ -11443,7 +11443,7 @@ msgid "" "Synchronizing AMS filaments will discard your modified but unsaved filament presets.\n" "Are you sure you want to continue?" msgstr "" -"AMS filamanlarının senkronize edilmesi, değiştirilmiş ancak kaydedilmemiş filaman ön ayarlarınızı siler.\n" +"AMS filamentlerinin senkronize edilmesi, değiştirilmiş ancak kaydedilmemiş filament ön ayarlarınızı siler.\n" "Devam etmek istediğinizden emin misiniz?" msgctxt "Sync_AMS" @@ -11470,10 +11470,10 @@ msgid "Overwriting" msgstr "Üzerine yazma" msgid "Reset all filament mapping" -msgstr "Tüm filaman eşlemesini sıfırla" +msgstr "Tüm filament eşlemesini sıfırla" msgid "(Recommended filament)" -msgstr "(Önerilen filaman)" +msgstr "(Önerilen filament)" msgid "Advanced Options" msgstr "Gelişmiş Seçenekler" @@ -11499,7 +11499,7 @@ msgid "Tip" msgstr "Uç" msgid "Only synchronize filament type and color, not including AMS slot information." -msgstr "AMS yuvası bilgileri hariç, yalnızca filaman tipini ve rengini senkronize edin." +msgstr "AMS yuvası bilgileri hariç, yalnızca filament tipini ve rengini senkronize edin." msgid "Replace the project filaments list sequentially based on printer filaments. And unused printer filaments will be automatically added to the end of the list." msgstr "Proje filamentleri listesini yazıcı filamentlerine göre sırayla değiştirin. Kullanılmayan yazıcı filamentleri ise otomatik olarak listenin sonuna eklenecektir." @@ -11514,7 +11514,7 @@ msgid "After being synced, this action cannot be undone." msgstr "Senkronize edildikten sonra bu işlem geri alınamaz." msgid "After being synced, the project's filament presets and colors will be replaced with the mapped filament types and colors. This action cannot be undone." -msgstr "Senkronize edildikten sonra projenin filaman ön ayarları ve renkleri, eşlenen filaman türleri ve renkleri ile değiştirilecektir. Bu eylem geri alınamaz." +msgstr "Senkronize edildikten sonra projenin filament ön ayarları ve renkleri, eşlenen filament türleri ve renkleri ile değiştirilecektir. Bu eylem geri alınamaz." msgid "Are you sure to synchronize the filaments?" msgstr "Filamentleri senkronize ettiğinizden emin misiniz?" @@ -11529,7 +11529,7 @@ msgid "Add unused filaments to filaments list." msgstr "Kullanılmayan filamentleri filament listesine ekleyin." msgid "Only synchronize filament type and color, not including slot information." -msgstr "Yuva bilgisi hariç, yalnızca filaman tipini ve rengini senkronize edin." +msgstr "Yuva bilgisi hariç, yalnızca filament tipini ve rengini senkronize edin." msgid "Ext spool" msgstr "Harici makara" @@ -11564,7 +11564,7 @@ msgid "Successfully synchronized filament color from printer." msgstr "Filament rengi yazıcıdan başarıyla senkronize edildi." msgid "Successfully synchronized color and type of filament from printer." -msgstr "Yazıcıdan filamanın rengi ve türü başarıyla senkronize edildi." +msgstr "Yazıcıdan filamentin rengi ve türü başarıyla senkronize edildi." msgctxt "FinishSyncAms" msgid "OK" @@ -11587,7 +11587,7 @@ msgid "For constant flow rate, hold %1% while dragging." msgstr "Sabit akış hızı için sürüklerken %1% basılı tutun." msgid "ms" -msgstr "Bayan" +msgstr "ms" msgid "Total ramming" msgstr "Toplam çarpma" @@ -11599,7 +11599,7 @@ msgid "Ramming line" msgstr "Çarpma hattı" msgid "Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences" -msgstr "Orca, filamentlerin rengi her değiştiğinde veya filamentler değiştiğinde yıkama hacimlerinizi yeniden hesaplar. Otomatik hesaplamayı Orca Dilimleyici > Tercihler'de devre dışı bırakabilirsiniz." +msgstr "Orca, filament rengi veya filament değiştirildiğinde tahliye miktarlarını her defasında yeniden hesaplar. Otomatik hesaplamayı Orca Slicer > Tercihler altından devre dışı bırakabilirsiniz" msgid "Flushing volume (mm³) for each filament pair." msgstr "Her filament çifti için yıkama hacmi (mm³)." @@ -11622,7 +11622,7 @@ msgid "Flushing volumes for filament change" msgstr "Filament değişimi için temizleme hacmi" msgid "Please choose the filament colour" -msgstr "Lütfen filaman rengini seçin" +msgstr "Lütfen filament rengini seçin" # AI Translated msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." @@ -11669,7 +11669,7 @@ msgid "parse json failed" msgstr "json ayrıştırma başarısız oldu" msgid "[Action Required] " -msgstr "[İşlem Gerekli]" +msgstr "[İşlem Gerekli] " msgid "[Action Required]" msgstr "[İşlem Gerekli]" @@ -11777,7 +11777,7 @@ msgid "Movement step set to 1mm" msgstr "Hareket adımı 1 mm'ye ayarlandı" msgid "Keyboard 1-9: set filament for object/part" -msgstr "klavye 1-9: nesne/parça için filamenti ayarlayın" +msgstr "Klavye 1-9: nesneye/parçaya filament ata" msgid "Camera view - Default" msgstr "Kamera görünümü - Varsayılan" @@ -12134,7 +12134,7 @@ msgid "Repair finished" msgstr "Onarım tamamlandı" msgid "Repair failed" -msgstr "Onarım başarısız oldu." +msgstr "Onarım başarısız oldu" msgid "Repair canceled" msgstr "Onarım iptal edildi" @@ -12156,7 +12156,7 @@ msgid "Open G-code file:" msgstr "G kodu dosyasını açın:" msgid "One object has an empty first layer and can't be printed. Please Cut the bottom or enable supports." -msgstr "Bir nesnenin başlangıç katmanı boş ve yazdırılamıyor. Lütfen alt kısmı kesin veya destekleri etkinleştirin." +msgstr "Bir nesnenin ilk katmanı boş ve yazdırılamıyor. Lütfen alt kısmı kesin veya destekleri etkinleştirin." #, boost-format msgid "The object has empty layers between %1% and %2% and can’t be printed." @@ -12167,7 +12167,7 @@ msgid "Object: %1%" msgstr "Nesne: %1%" msgid "Parts of the object at these heights may be too thin or the object may have a faulty mesh." -msgstr "Belki nesnenin bu yükseklikteki bazı kısımları çok incedir veya nesnenin ağı hatalı olabilir" +msgstr "Nesnenin bu yüksekliklerdeki kısımları çok ince olabilir veya nesne bozuk bir ağ yapısına (mesh) sahip olabilir." # AI Translated msgid "Process change extrusion role G-code" @@ -12178,7 +12178,7 @@ msgid "Filament change extrusion role G-code" msgstr "Filament ekstrüzyon rolü değişim G-code'u" msgid "No object can be printed. It may be too small." -msgstr "Hiçbir nesne yazdırılamaz. Belki çok küçük" +msgstr "Hiçbir nesne basılamıyor. Nesne çok küçük olabilir." msgid "Your print is very close to the priming regions. Make sure there is no collision." msgstr "Baskınız hazırlama bölgelerine çok yakın. Çarpışma olmadığından emin olun." @@ -12217,10 +12217,10 @@ msgid "Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2." msgstr "Input shaping yalnızca Klipper, RepRapFirmware ve Marlin 2 tarafından desteklenir." msgid "Grouping error: " -msgstr "Gruplama hatası:" +msgstr "Gruplama hatası: " msgid " can not be placed in the " -msgstr "içine yerleştirilemez" +msgstr " içine yerleştirilemez " # AI Translated msgid "Group error in manual mode. Please check nozzle count or regroup." @@ -12236,7 +12236,7 @@ msgid "too many files" msgstr "çok fazla dosya" msgid "File too large" -msgstr "dosya çok büyük" +msgstr "Dosya çok büyük" msgid "unsupported method" msgstr "desteklenmeyen yöntem" @@ -12306,7 +12306,7 @@ msgid "invalid filename" msgstr "geçersiz dosya adı" msgid "Buffer too small" -msgstr "arabellek çok küçük" +msgstr "Arabellek çok küçük" msgid "internal error" msgstr "dahili hata" @@ -12315,7 +12315,7 @@ msgid "file not found" msgstr "dosya bulunamadı" msgid "Archive too large" -msgstr "arşiv çok büyük" +msgstr "Arşiv çok büyük" msgid "validation failed" msgstr "doğrulama başarısız" @@ -12339,7 +12339,7 @@ msgid " is too close to exclusion area, there may be collisions when printing." msgstr " Hariç tutma alanına çok yakın olduğundan yazdırma sırasında çarpışmalar meydana gelebilir." msgid " is too close to clumping detection area, there may be collisions when printing." -msgstr "topaklanma algılama alanına çok yakın olduğundan yazdırma sırasında çarpışmalar meydana gelebilir." +msgstr " topaklanma algılama alanına çok yakın, baskı sırasında çarpışmalar meydana gelebilir." msgid "Prime Tower" msgstr "Başbakan Kulesi" @@ -12351,7 +12351,7 @@ msgid " is too close to an exclusion area, and collisions will be caused.\n" msgstr " dışlama alanına çok yakın ve çarpışmalara neden olacak.\n" msgid " is too close to clumping detection area, and collisions will be caused.\n" -msgstr "topaklanma tespit alanına çok yakınsa çarpışmalara neden olur.\n" +msgstr " topaklanma algılama alanına çok yakın, çarpışmalar meydana gelecektir.\n" # AI Translated msgid "Selected nozzle temperatures are incompatible. Each filament's nozzle temperature must fall within the recommended nozzle temperature range of the other filaments. Otherwise, nozzle clogging or printer damage may occur." @@ -12405,7 +12405,7 @@ msgid "Variable layer height is not supported with Organic supports." msgstr "Değişken katman yüksekliği Organik desteklerle desteklenmez." msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." -msgstr "Farklı püskürtme ucu çapları ve farklı filaman çapları, ana kule etkinleştirildiğinde iyi çalışmayabilir. Oldukça deneysel olduğundan lütfen dikkatli ilerleyin." +msgstr "Farklı püskürtme ucu çapları ve farklı filament çapları, ana kule etkinleştirildiğinde iyi çalışmayabilir. Oldukça deneysel olduğundan lütfen dikkatli ilerleyin." msgid "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)." msgstr "Temizleme Kulesi şu anda yalnızca ilgili ekstruder adreslemesiyle desteklenmektedir (use_relative_e_distances=1)." @@ -12794,7 +12794,7 @@ msgid "This is the bed temperature for layers except for the first one. A value msgstr "İlk katman dışındaki katmanlar için yatak sıcaklığı. 0 Değeri, filamentin Dokulu PEI Plaka üzerine yazdırmayı desteklemediği anlamına gelir." msgid "First layer" -msgstr "Başlangıç katmanı" +msgstr "İlk katman" msgid "First layer bed temperature" msgstr "İlk katman yatak sıcaklığı" @@ -12818,7 +12818,7 @@ msgid "This is the bed temperature of the first layer. A value of 0 means the fi msgstr "İlk katmanın yatak sıcaklığı. 0 Değeri, filamentin Dokulu PEI Plaka üzerine yazdırmayı desteklemediği anlamına gelir." msgid "Plate types supported by the printer" -msgstr "Yazıcının desteklediği yatak türleri." +msgstr "Yazıcı tarafından desteklenen plaka tipleri" msgid "Default bed type" msgstr "Varsayılan yatak türü" @@ -13130,7 +13130,7 @@ msgid "" msgstr "" "Bu faktör dış duvarlar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek dış duvar akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek dış duvar akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Inner wall flow ratio" msgstr "İç duvar akış oranı" @@ -13142,7 +13142,7 @@ msgid "" msgstr "" "Bu faktör iç duvarlar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek iç duvar akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek iç duvar akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Overhang flow ratio" msgstr "Çıkıntı akış oranı" @@ -13154,7 +13154,7 @@ msgid "" msgstr "" "Bu faktör çıkıntılar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek sarkma akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek sarkma akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Sparse infill flow ratio" msgstr "Seyrek dolgu akış oranı" @@ -13166,7 +13166,7 @@ msgid "" msgstr "" "Bu faktör seyrek dolgu için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek seyrek dolgu akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek seyrek dolgu akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Internal solid infill flow ratio" msgstr "Dahili katı dolgu akış oranı" @@ -13178,7 +13178,7 @@ msgid "" msgstr "" "Bu faktör, iç katı dolgu için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek dahili katı dolgu akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek dahili katı dolgu akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Gap fill flow ratio" msgstr "Boşluk doldurma akış oranı" @@ -13190,7 +13190,7 @@ msgid "" msgstr "" "Bu faktör boşlukları dolduracak malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek boşluk doldurma akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek boşluk doldurma akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Support flow ratio" msgstr "Destek akış oranı" @@ -13202,7 +13202,7 @@ msgid "" msgstr "" "Bu faktör destek için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek destek akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek destek akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Support interface flow ratio" msgstr "Destek arayüzü akış oranı" @@ -13214,7 +13214,7 @@ msgid "" msgstr "" "Bu faktör, destek arayüzü için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek destek arayüzü akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek destek arayüzü akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Precise wall" msgstr "Hassas duvar" @@ -13236,7 +13236,7 @@ msgid "" "If a top surface has to be printed and it's partially covered by another layer, it won't be considered at a top layer where its width is below this value. This can be useful to not let the 'one perimeter on top' trigger on surface that should be covered only by perimeters. This value can be a mm or a % of the perimeter extrusion width.\n" "Warning: If enabled, artifacts can be created if you have some thin features on the next layer, like letters. Set this setting to 0 to remove these artifacts." msgstr "" -"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından kaplıysa layer genişliği bu değerin altında olan bir üst katman olarak değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir çevre üstte' tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya a % çevre ekstrüzyon genişliğinin bir yüzdesi olabilir.\n" +"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından kaplıysa katman genişliği bu değerin altında olan bir üst katman olarak değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir çevre üstte' tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya a % çevre ekstrüzyon genişliğinin bir yüzdesi olabilir.\n" "Uyarı: Etkinleştirilirse bir sonraki katmanda harfler gibi bazı ince özelliklerin olması durumunda yapay yapılar oluşturulabilir. Bu yapıları kaldırmak için bu ayarı 0 olarak ayarlayın." msgid "Only one wall on first layer" @@ -13712,7 +13712,7 @@ msgid "Add end G-code when finishing the printing of this filament." msgstr "Bu filament ile baskı bittiğinde çalışacak G kod." msgid "Ensure vertical shell thickness" -msgstr "Dikey kabuk kalınlığını onayla" +msgstr "Dikey kabuk kalınlığını koru" msgid "" "Add solid infill near sloping surfaces to guarantee the vertical shell thickness (top+bottom solid layers)\n" @@ -14185,10 +14185,10 @@ msgid "Minimum HRC of nozzle required to print the filament. A value of 0 means msgstr "Filamenti yazdırmak için gereken minimum HRC nozul. Sıfır, nozulun HRC'sinin kontrol edilmediği anlamına gelir." msgid "Filament map to extruder" -msgstr "Ekstrudere filaman haritası" +msgstr "Ekstrudere filament haritası" msgid "Filament map to extruder." -msgstr "Ekstrudere filaman haritası." +msgstr "Ekstrudere filament haritası." msgid "Auto For Flush" msgstr "Yıkama İçin Otomatik" @@ -14204,7 +14204,7 @@ msgid "Flush temperature" msgstr "Yıkama sıcaklığı" msgid "Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range." -msgstr "Filament yıkanırken sıcaklık. 0, önerilen meme sıcaklık aralığının üst sınırını gösterir." +msgstr "Filament yıkanırken sıcaklık. 0, önerilen nozul sıcaklık aralığının üst sınırını gösterir." # AI Translated msgid "Flush temperature used in fast purge mode." @@ -14326,7 +14326,7 @@ msgid "Speed used for unloading the filament on the wipe tower (does not affect msgstr "Filamenti silme kulesinde boşaltmak için kullanılan hız (sıkıştırmadan hemen sonra boşaltmanın ilk kısmını etkilemez)." msgid "Unloading speed at the start" -msgstr "Başlangıçta boşaltma hızı" +msgstr "Başlangıçtaki boşaltma hızı" msgid "Speed used for unloading the tip of the filament immediately after ramming." msgstr "Sıkıştırmadan hemen sonra filamentin ucunu boşaltmak için kullanılan hız." @@ -14353,7 +14353,7 @@ msgid "Stamping distance measured from the center of the cooling tube" msgstr "Soğutma tüpünün merkezinden ölçülen damgalama mesafesi" msgid "If set to non-zero value, filament is moved toward the nozzle between the individual cooling moves (\"stamping\"). This option configures how long this movement should be before the filament is retracted again." -msgstr "Sıfırdan farklı bir değere ayarlanırsa filaman bireysel soğutma hareketleri arasında (“damgalama”) nüzule doğru hareket ettirilir. Bu seçenek, filamanın tekrar geri çekilmesinden önce bu hareketin ne kadar sürmesi gerektiğini yapılandırır." +msgstr "Sıfırdan farklı bir değere ayarlanırsa filament bireysel soğutma hareketleri arasında (“damgalama”) nüzule doğru hareket ettirilir. Bu seçenek, filamentin tekrar geri çekilmesinden önce bu hareketin ne kadar sürmesi gerektiğini yapılandırır." msgid "Speed of the first cooling move" msgstr "İlk soğutma hareketi hızı" @@ -14448,7 +14448,7 @@ msgid "g/cm³" msgstr "g/cm³" msgid "Filament material type" -msgstr "Filament malzeme türü." +msgstr "Filament malzeme türü" msgid "Soluble material" msgstr "Çözünür malzeme" @@ -14460,7 +14460,7 @@ msgid "Filament ramming length" msgstr "Filament sıkıştırma uzunluğu" msgid "When changing the extruder, it is recommended to extrude a certain length of filament from the original extruder. This helps minimize nozzle oozing." -msgstr "Ekstrüderi değiştirirken, orijinal ekstrüderden belirli bir uzunlukta filamanın çıkarılması tavsiye edilir. Bu, meme sızıntısını en aza indirmeye yardımcı olur." +msgstr "Ekstrüderi değiştirirken, orijinal ekstrüderden belirli bir uzunlukta filamentin çıkarılması tavsiye edilir. Bu, nozul sızıntısını en aza indirmeye yardımcı olur." msgid "Support material" msgstr "Destek malzemesi" @@ -14586,7 +14586,7 @@ msgid "Sparse infill pattern" msgstr "Dolgu deseni" msgid "This is the line pattern for internal sparse infill." -msgstr "İç dolgu deseni." +msgstr "Bu, iç seyrek dolgu için çizgi desenidir." msgid "Zig Zag" msgstr "Zig zag" @@ -14663,7 +14663,7 @@ msgid "Acceleration of internal solid infill. If the value is expressed as a per msgstr "İç katı dolgunun hızlandırılması. Değer yüzde olarak ifade edilirse (örn. %100), varsayılan ivmeye göre hesaplanacaktır." msgid "This is the printing acceleration for the first layer. Using limited acceleration can improve build plate adhesion." -msgstr "Başlangıç katmanının hızlandırılması. Daha düşük bir değerin kullanılması baskı plakası yapışkanlığını iyileştirebilir." +msgstr "İlk katman için baskı ivmelenmesidir. Sınırlı bir ivmelenme kullanmak, baskı tablasına yapışmayı artırabilir." msgid "Enable accel_to_decel" msgstr "Accel_to_decel'i etkinleştir" @@ -14714,7 +14714,7 @@ msgid "Line width of the first layer. If expressed as a %, it will be computed o msgstr "İlk katmanın çizgi genişliği. % olarak ifade edilirse Nozul çapı üzerinden hesaplanacaktır." msgid "First layer height" -msgstr "Başlangıç katman yüksekliği" +msgstr "İlk katman yüksekliği" msgid "Height of the first layer. Making the first layer height thicker can improve build plate adhesion." msgstr "İlk katmanın yüksekliği. İlk katman yüksekliğini biraz kalın yapmak, baskı plakasının yapışmasını iyileştirebilir." @@ -14723,7 +14723,7 @@ msgid "This is the speed for the first layer except for solid infill sections." msgstr "Katı dolgu kısmı dışındaki ilk katmanın hızı." msgid "First layer infill" -msgstr "Başlangıç katman dolgusu" +msgstr "İlk katman dolgusu" msgid "This is the speed for solid infill parts of the first layer." msgstr "İlk katmanın katı dolgu kısmının hızı." @@ -14745,7 +14745,7 @@ msgid "First layer nozzle temperature" msgstr "İlk katman nozul sıcaklığı" msgid "Nozzle temperature for printing the first layer with this filament" -msgstr "Bu filamenti kullanırken ilk katmanı yazdırmak için nozul sıcaklığı." +msgstr "Bu filament ile ilk katmanı basmak için nozul sıcaklığı" msgid "Full fan speed at layer" msgstr "Maksimum fan hızı" @@ -14813,25 +14813,25 @@ msgid "Ironing flow" msgstr "Ütüleme akışı" msgid "Filament-specific override for ironing flow. This allows you to customize the ironing flow for each filament type. Too high value results in overextrusion on the surface." -msgstr "Ütüleme akışı için filamana özgü geçersiz kılma. Bu, her filaman türü için ütüleme akışını özelleştirmenize olanak tanır. Çok yüksek değer yüzeyde aşırı ekstrüzyona neden olur." +msgstr "Ütüleme akışı için filamente özgü geçersiz kılma. Bu, her filament türü için ütüleme akışını özelleştirmenize olanak tanır. Çok yüksek değer yüzeyde aşırı ekstrüzyona neden olur." msgid "Ironing line spacing" msgstr "Ütüleme çizgi aralığı" msgid "Filament-specific override for ironing line spacing. This allows you to customize the spacing between ironing lines for each filament type." -msgstr "Ütüleme hattı aralığı için filamente özel geçersiz kılma. Bu, her filaman türü için ütüleme çizgileri arasındaki boşluğu özelleştirmenize olanak tanır." +msgstr "Ütüleme hattı aralığı için filamente özel geçersiz kılma. Bu, her filament türü için ütüleme çizgileri arasındaki boşluğu özelleştirmenize olanak tanır." msgid "Ironing inset" msgstr "Ütüleme boşluğu" msgid "Filament-specific override for ironing inset. This allows you to customize the distance to keep from the edges when ironing for each filament type." -msgstr "İç parçayı ütülemek için filamente özel geçersiz kılma. Bu, her filaman türü için ütüleme sırasında kenarlardan korunacak mesafeyi özelleştirmenize olanak tanır." +msgstr "İç parçayı ütülemek için filamente özel geçersiz kılma. Bu, her filament türü için ütüleme sırasında kenarlardan korunacak mesafeyi özelleştirmenize olanak tanır." msgid "Ironing speed" msgstr "Ütüleme hızı" msgid "Filament-specific override for ironing speed. This allows you to customize the print speed of ironing lines for each filament type." -msgstr "Ütüleme hızı için filamana özgü geçersiz kılma. Bu, her filaman türü için ütüleme hatlarının baskı hızını özelleştirmenize olanak tanır." +msgstr "Ütüleme hızı için filamente özgü geçersiz kılma. Bu, her filament türü için ütüleme hatlarının baskı hızını özelleştirmenize olanak tanır." msgid "This setting makes the toolhead randomly jitter while printing walls so that the surface has a rough textured look. This setting controls the fuzzy position." msgstr "Duvara baskı yaparken rastgele titreme, böylece yüzeyin pürüzlü bir görünüme sahip olması. Bu ayar pütürlü konumu kontrol eder." @@ -14884,8 +14884,8 @@ msgid "" "Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop. At the same time, the width of the extrusion for a particular layer should also not be below a certain level. It is usually equal 15-25%% of a layer height. Therefore, the maximum fuzzy skin thickness with a perimeter width of 0.4 mm and a layer height of 0.2 mm will be 0.4-(0.2*0.25)=±0.35mm! If you enter a higher parameter than this, the error Flow::spacing() will displayed, and the model will not be sliced. You can choose this number until this error is repeated." msgstr "" "Pütürlü yüzey oluşturma modu. Sadece Arachne ile çalışır!\n" -"Yer Değiştirme: Desen, nozülün orijinal yoldan yana kaydırılmasıyla oluşturulduğu klasik mod.\n" -"Ekstrüzyon: Desenin ekstrüde edilen plastik miktarına göre oluşturulduğu mod. Bu, nozül sarsıntısı olmadan pürüzsüz bir desen veren hızlı ve düz bir algoritmadır. Ancak, tüm dizilimde gevşek duvarlar oluşturmak için daha kullanışlıdır.\n" +"Yer Değiştirme: Desen, nozulun orijinal yoldan yana kaydırılmasıyla oluşturulduğu klasik mod.\n" +"Ekstrüzyon: Desenin ekstrüde edilen plastik miktarına göre oluşturulduğu mod. Bu, nozul sarsıntısı olmadan pürüzsüz bir desen veren hızlı ve düz bir algoritmadır. Ancak, tüm dizilimde gevşek duvarlar oluşturmak için daha kullanışlıdır.\n" "Birleşik: Eklem modu [Yer Değiştirme] + [Ekstrüzyon]. Duvarların görünümü [Yer Değiştirme] Moduna benzer, ancak çevreler arasında gözenek bırakmaz.\n" "\n" "Dikkat! [Ekstrüzyon] ve [Birleşik] modları yalnızca fuzzy_skin_thickness parametresini çalıştırır, yazdırılan ilmeğin kalınlığından daha fazla olmamalıdır. Aynı zamanda, belirli bir katman için ekstrüzyon genişliği de belirli bir seviyenin altında olmamalıdır. Genellikle katman yüksekliğinin %%15-25'ine eşittir. Bu nedenle, 0,4 mm çevre genişliği ve 0,2 mm katman yüksekliğine sahip maksimum pütürlü yüzey kalınlığı 0,4-(0,2*0,25)=±0,35 mm olacaktır! Bundan daha yüksek bir parametre girerseniz, Flow::spacing() hatası görüntülenir ve model dilimlenmez. Bu hata tekrarlanana kadar bu sayıyı seçebilirsiniz." @@ -15251,7 +15251,7 @@ msgid "Sparse infill rotation template" msgstr "Seyrek dolgu döndürme şablonu" msgid "Rotate the sparse infill direction per layer using a template of angles. Enter comma-separated degrees (e.g., '0,30,60,90'). Angles are applied in order by layer and repeat when the list ends. Advanced syntax is supported: '+5' rotates +5° every layer; '+5#5' rotates +5° every 5 layers. See the Wiki for details. When a template is set, the standard infill direction setting is ignored. Note: some infill patterns (e.g., Gyroid) control rotation themselves; use with care." -msgstr "Seyrek dolgu yönünü katman katman açı şablonuna göre döndürün. Virgülle ayrılmış açıları girin (örn. '0,30,60,90'). Açılar katman sırasına göre uygulanır ve liste sona erdiğinde tekrarlanır. Gelişmiş sözdizimi desteklenir: '+5' her katmanda +5° döndürür; '+5#5' her 5 katmanda +5° döndürür. Detaylar için Viki’ye bakın. Bir şablon ayarlandığında, standart dolgu yönü ayarı yok sayılır. NOT: bazı dolgu desenleri (örn. Gyroid) kendi döndürmesini kontrol eder; dikkatli kullanın" +msgstr "Açı şablonu kullanarak seyrek dolgu yönünü katman bazında döndürün. Virgülle ayrılmış açılar girin (ör. '0,30,60,90'). Açılar katman sırasına göre uygulanır ve liste bittiğinde tekrarlanır. Gelişmiş sözdizimi desteklenir: '+5' her katmanda +5° döndürür; '+5#5' her 5 katmanda bir +5° döndürür. Detaylar için Wiki'ye bakın. Bir şablon ayarlandığında, standart dolgu yönü ayarı göz ardı edilir. Not: Bazı dolgu desenleri (ör. Gyroid) dönmeyi kendisi kontrol eder; dikkatli kullanın." msgid "Solid infill rotation template" msgstr "Katı dolgu döndürme şablonu" @@ -15263,7 +15263,7 @@ msgid "Skeleton infill density" msgstr "İskelet dolgu yoğunluğu" msgid "The remaining part of the model contour after removing a certain depth from the surface is called the skeleton. This parameter is used to adjust the density of this section. When two regions have the same sparse infill settings but different skeleton densities, their skeleton areas will develop overlapping sections. Default is as same as infill density." -msgstr "üzeyden belirli bir derinlik çıkarıldıktan sonra model konturunda kalan kısma 'iskelet' denir. Bu parametre, bu bölümün yoğunluğunu ayarlamak için kullanılır. İki bölge aynı seyrek dolgu ayarlarına sahip fakat farklı iskelet yoğunluklarına sahipse, iskelet alanları üst üste binen bölümler oluşturabilir. Varsayılan değer, dolgu yoğunluğu ile aynıdır." +msgstr "Yüzeyden belirli bir derinlik çıkarıldıktan sonra model hatlarının geriye kalan kısmına iskelet adı verilir. Bu parametre, söz konusu alanın yoğunluğunu ayarlamak için kullanılır. İki bölge aynı seyrek dolgu ayarlarına ancak farklı iskelet yoğunluklarına sahip olduğunda, iskelet alanlarında çakışan kesitler oluşur. Varsayılan değer dolgu yoğunluğu ile aynıdır." msgid "Skin infill density" msgstr "Yüzey dolgu yoğunluğu" @@ -15494,7 +15494,7 @@ msgid "The distance from the boundary between filaments to generate interlocking msgstr "Hücrelerde ölçülen, birbirine kenetlenen yapıyı oluşturmak için filamentler arasındaki sınırdan mesafe. Çok az hücre yapışmanın zayıf olmasına neden olur." msgid "Interlocking boundary avoidance" -msgstr "Birbirine kenetlenen sınırdan kaçınma" +msgstr "Kenetleme sınır mesafesi koruması" msgid "The distance from the outside of a model where interlocking structures will not be generated, measured in cells." msgstr "Birbirine kenetlenen yapıların oluşturulmayacağı bir modelin dışına olan mesafe, hücrelerde ölçülür." @@ -15530,7 +15530,7 @@ msgid "This is the distance between the lines used for ironing." msgstr "Ütü çizgileri arasındaki mesafe." msgid "The distance to keep from the edges. A value of 0 sets this to half of the nozzle diameter." -msgstr "Kenarlardan korunacak mesafe. 0 değeri bunu nozül çapının yarısına ayarlar." +msgstr "Kenarlardan korunacak mesafe. 0 değeri bunu nozul çapının yarısına ayarlar." msgid "This is the print speed for ironing lines." msgstr "Ütüleme çizgilerinin baskı hızı." @@ -15608,7 +15608,7 @@ msgid "Silent Mode" msgstr "Sessiz mod" msgid "Whether the machine supports silent mode in which machine uses lower acceleration to print more quietly" -msgstr "Makinenin yazdırmak için daha düşük hızlanma kullandığı sessiz modu destekleyip desteklemediği." +msgstr "Daha sessiz baskı için ivmelenmeyi düşüren sessiz mod desteği" msgid "Emit limits to G-code" msgstr "G-kod sınırları" @@ -15881,7 +15881,7 @@ msgstr "" "RRF: X ve Y değerleri eşittir." msgid "Hz" -msgstr "Hz." +msgstr "Hz" msgid "Y" msgstr "Y" @@ -16038,7 +16038,7 @@ msgid "Nozzle volume" msgstr "Nozul hacmi" msgid "Volume of nozzle between the filament cutter and the end of the nozzle" -msgstr "Kesici ile nozulun ucu arasındaki nozul hacmi." +msgstr "Filament kesici ile nozul ucu arasındaki nozul hacmi" msgid "Cooling tube position" msgstr "Soğutma borusu konumu" @@ -16217,7 +16217,7 @@ msgid "This expands all raft layers in XY plane." msgstr "XY düzlemindeki tüm rafa katmanlarını genişlet." msgid "First layer density" -msgstr "Başlangıç katman yoğunluğu" +msgstr "İlk katman yoğunluğu" msgid "This is the density of the first raft or support layer." msgstr "İlk sal veya destek katmanının yoğunluğu." @@ -16404,7 +16404,7 @@ msgid "Deretraction speed" msgstr "İleri itme hızı" msgid "Speed for reloading filament into the nozzle. Zero means same speed of retraction." -msgstr "Filamentin nozüle yeniden yüklenme hızı. Sıfır, geri çekilme hızının aynı olduğu anlamına gelir." +msgstr "Filamentin nozule yeniden yüklenme hızı. Sıfır, geri çekilme hızının aynı olduğu anlamına gelir." # AI Translated msgid "Deretraction speed (extruder change)" @@ -16467,16 +16467,16 @@ msgstr "" "Bu miktar milimetre cinsinden veya mevcut ekstruder çapının yüzdesi olarak belirtilebilir. Bu parametrenin varsayılan değeri %10'dur." msgid "Scarf joint seam (beta)" -msgstr "Eğik birleşim dikişi (beta)" +msgstr "Atkı dikişi birleşimi (beta)" msgid "Use scarf joint to minimize seam visibility and increase seam strength." -msgstr "Dikiş görünürlüğünü en aza indirmek ve dikiş mukavemetini arttırmak için eğik birleşimini kullanın." +msgstr "Dikiş izini en aza indirmek ve dikiş mukavemetini artırmak için atkı dikişi kullanın." msgid "Conditional scarf joint" -msgstr "Koşullu eğik birleşimi" +msgstr "Koşullu atkı dikişi" msgid "Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively." -msgstr "Eğik bağlantılarını yalnızca geleneksel dikişlerin keskin köşelerdeki dikişleri etkili bir şekilde gizleyemediği düzgün kenarlara uygulayın." +msgstr "Atkı dikişini yalnızca, geleneksel dikişlerin keskin köşelerde gizlenemediği düz çevre hatlarına uygular." msgid "Conditional angle threshold" msgstr "Koşullu açı eşiği" @@ -16485,61 +16485,61 @@ msgid "" "This option sets the threshold angle for applying a conditional scarf joint seam.\n" "If the maximum angle within the perimeter loop exceeds this value (indicating the absence of sharp corners), a scarf joint seam will be used. The default value is 155°." msgstr "" -"Bu seçenek, koşullu bir eğik eklem dikişi uygulamak için eşik açısını ayarlar.\n" -"Çevre halkası içindeki maksimum açı bu değeri aşarsa (keskin köşelerin bulunmadığını gösterir), bir eğik birleştirme dikişi kullanılacaktır. Varsayılan değer 155°'dir." +"Bu seçenek, koşullu atkı dikişinin uygulanacağı eşik açısını belirler.\n" +"Çevre döngüsü içindeki maksimum açı bu değeri aşarsa (keskin köşelerin olmadığını gösterir), atkı dikişi kullanılır. Varsayılan değer 155°'dir." msgid "Conditional overhang threshold" msgstr "Koşullu çıkıntı eşiği" #, no-c-format, no-boost-format msgid "This option determines the overhang threshold for the application of scarf joint seams. If the unsupported portion of the perimeter is less than this threshold, scarf joint seams will be applied. The default threshold is set at 40% of the external wall's width. Due to performance considerations, the degree of overhang is estimated." -msgstr "Bu seçenek, eğik bağlantı dikişlerinin uygulanması için sarkma eşiğini belirler. Çevrenin desteklenmeyen kısmı bu eşikten az ise eğik birleştirme dikişleri uygulanacaktır. Varsayılan eşik, dış duvar genişliğinin %40'ına ayarlanmıştır. Performans değerlendirmeleri nedeniyle çıkıntının derecesi tahmin edilir." +msgstr "Bu seçenek, atkı dikişlerinin uygulanacağı çıkıntı eşiğini belirler. Çevrenin desteklenmeyen kısmı bu eşikten azsa, atkı dikişi uygulanır. Varsayılan eşik değeri, dış duvar genişliğinin %40'ı olarak ayarlanmıştır. Performans değerlendirmeleri nedeniyle çıkıntı derecesi tahmini olarak hesaplanır." msgid "Scarf joint speed" -msgstr "Eğik birleşim hızı" +msgstr "Atkı dikişi hızı" msgid "This option sets the printing speed for scarf joints. It is recommended to print scarf joints at a slow speed (less than 100 mm/s). It's also advisable to enable 'Extrusion rate smoothing' if the set speed varies significantly from the speed of the outer or inner walls. If the speed specified here is higher than the speed of the outer or inner walls, the printer will default to the slower of the two speeds. When specified as a percentage (e.g., 80%), the speed is calculated based on the respective outer or inner wall speed. The default value is set to 100%." -msgstr "Bu seçenek, eğik bağlantılarının yazdırma hızını ayarlar. Eğik bağlantılarının yavaş bir hızda (100 mm/s'den az) yazdırılması tavsiye edilir. Ayarlanan hızın dış veya iç duvarların hızından önemli ölçüde farklı olması durumunda 'Ekstrüzyon hızı yumuşatma' seçeneğinin etkinleştirilmesi de tavsiye edilir. Burada belirtilen hız, dış veya iç duvarların hızından daha yüksekse, yazıcı varsayılan olarak iki hızdan daha yavaş olanı seçecektir. Yüzde olarak belirtildiğinde (örn. %80), hız, ilgili dış veya iç duvar hızına göre hesaplanır. Varsayılan değer %100 olarak ayarlanmıştır." +msgstr "Bu seçenek, atkı birleşimlerinin baskı hızını belirler. Atkı birleşimlerinin düşük hızlarda (100 mm/s altında) basılması önerilir. Belirlenen hız, dış veya iç duvar hızından belirgin şekilde farklıysa 'Akış hızı yumuşatma' özelliğinin etkinleştirilmesi tavsiye edilir. Buradaki hız dış veya iç duvar hızından daha yüksekse, yazıcı varsayılan olarak bu iki hızdan yavaş olanı kullanır. Yüzde olarak belirtildiğinde (ör. %80), hız ilgili dış veya iç duvar hızına göre hesaplanır. Varsayılan değer %100 olarak ayarlanmıştır." msgid "Scarf joint flow ratio" -msgstr "Eğik birleşimi akış oranı" +msgstr "Atkı dikişi akış oranı" msgid "This factor affects the amount of material for scarf joints." -msgstr "Bu faktör eğik birleşimlerinde kullanılacak materyal miktarını değiştirir." +msgstr "Bu faktör, atkı dikişleri için kullanılacak malzeme miktarını etkiler." msgid "Scarf start height" -msgstr "Eğik başlangıç yüksekliği" +msgstr "Atkı başlangıç yüksekliği" msgid "" "Start height of the scarf.\n" "This amount can be specified in millimeters or as a percentage of the current layer height. The default value for this parameter is 0." msgstr "" -"Eğik başlangıç yüksekliği.\n" -"Bu miktar milimetre cinsinden veya geçerli katman yüksekliğinin yüzdesi olarak belirtilebilir. Bu parametrenin varsayılan değeri 0'dır." +"Atkı başlangıç yüksekliği.\n" +"Bu değer milimetre cinsinden veya mevcut katman yüksekliğinin yüzdesi olarak belirtilebilir. Varsayılan değer 0'dır." msgid "Scarf around entire wall" -msgstr "Tüm duvarın etrafına atkıla" +msgstr "Tüm duvara atkı uygula" msgid "The scarf extends to the entire length of the wall." -msgstr "Eğik duvarın tüm uzunluğu boyunca uzanır." +msgstr "Atkı birleşimi, duvarın tüm uzunluğu boyunca uzanacak şekilde genişletilir." msgid "Scarf length" -msgstr "Eğik uzunluğu" +msgstr "Atkı dikişi uzunluğu" msgid "Length of the scarf. Setting this parameter to zero effectively disables the scarf." -msgstr "Atkının uzunluğu. Bu parametrenin 0 a ayarlanması atkıyı dolaylı yoldan devre dışı bırakır." +msgstr "Atkı birleşiminin uzunluğudur. Bu parametrenin 0 (sıfır) olarak ayarlanması atkı dikişini devre dışı bırakır." msgid "Scarf steps" -msgstr "Eğik kademesi" +msgstr "Atkı adımları" msgid "Minimum number of segments of each scarf." -msgstr "Her atkının minimum segment sayısı." +msgstr "Her bir atkının minimum segment sayısı." msgid "Scarf joint for inner walls" -msgstr "İç duvarlar için eğik birleşimi" +msgstr "İç duvarlar için atkı dikişi" msgid "Use scarf joint for inner walls as well." -msgstr "İç duvarlar için de eğik birleşimini kullanın." +msgstr "İç duvarlarda da atkı dikişi kullan." msgid "Role base wipe speed" msgstr "Otomatik temizleme hızı" @@ -16587,7 +16587,7 @@ msgid "Skirt height" msgstr "Etek yüksekliği" msgid "Number of skirt layers: usually only one" -msgstr "Etek katman sayısı. Genellikle tek katman." +msgstr "Etek katman sayısı: Genelde tek katman" msgid "Single loop after first layer" msgstr "İlk katmandan sonra tek duvar" @@ -16642,7 +16642,7 @@ msgid "" "Using a non-zero value is useful if the printer is set up to print without a prime line.\n" "Final number of loops is not taking into account while arranging or validating objects distance. Increase loop number in such case." msgstr "" -"Etek yazdırılırken mm cinsinden minimum filaman ekstrüzyon uzunluğu. Sıfır, bu özelliğin devre dışı olduğu anlamına gelir.\n" +"Etek yazdırılırken mm cinsinden minimum filament ekstrüzyon uzunluğu. Sıfır, bu özelliğin devre dışı olduğu anlamına gelir.\n" "\n" "Yazıcı ana hat olmadan yazdırmak üzere ayarlanmışsa sıfır dışında bir değer kullanmak yararlı olur.\n" "Nihai döngü sayısı, nesnelerin mesafesini düzenlerken veya doğrularken dikkate alınmaz. Böyle bir durumda döngü sayısını artırın." @@ -16700,7 +16700,7 @@ msgstr "Maksimum XY yumuşatma" #, no-c-format, no-boost-format msgid "Maximum distance to move points in XY to try to achieve a smooth spiral. If expressed as a %, it will be computed over nozzle diameter." -msgstr "Düzgün bir spiral elde etmek için XY'deki noktaları hareket ettirmek için maksimum mesafe % olarak ifade edilirse nozül çapı üzerinden hesaplanacaktır." +msgstr "Düzgün bir spiral elde etmek için XY'deki noktaları hareket ettirmek için maksimum mesafe % olarak ifade edilirse nozul çapı üzerinden hesaplanacaktır." msgid "Spiral starting flow ratio" msgstr "Spiral başlangıç akış oranı" @@ -16756,7 +16756,7 @@ msgid "Insert multiple preheat commands (e.g. M104.1). Only useful for Prusa XL. msgstr "Birden fazla ön ısıtma komutu ekleyin (örn. M104.1). Yalnızca Prusa XL için kullanışlıdır. Diğer yazıcılar için lütfen 1’e ayarlayın." msgid "G-code written at the very top of the output file, before any other content. Useful for adding metadata that printer firmware reads from the first lines of the file (e.g. estimated print time, filament usage). Supports placeholders like {print_time_sec} and {used_filament_length}." -msgstr "G kodu, çıktı dosyasının en üstünde, diğer içeriklerden önce yazılır. Yazıcı ürün yazılımının dosyanın ilk satırlarından okuduğu meta verileri (ör. tahmini yazdırma süresi, filaman kullanımı) eklemek için kullanışlıdır. {print_time_sec} ve {used_filament_length} gibi yer tutucuları destekler." +msgstr "G kodu, çıktı dosyasının en üstünde, diğer içeriklerden önce yazılır. Yazıcı ürün yazılımının dosyanın ilk satırlarından okuduğu meta verileri (ör. tahmini yazdırma süresi, filament kullanımı) eklemek için kullanışlıdır. {print_time_sec} ve {used_filament_length} gibi yer tutucuları destekler." msgid "Start G-code" msgstr "Başlangıç G Kodu" @@ -16765,7 +16765,7 @@ msgid "G-code added when starting a print." msgstr "Baskı başladığında çalışacak G Kodu." msgid "G-code added when the printer starts using this filament" -msgstr "Bu filament ile baskı başladığında çalıştırılacak G-Kod." +msgstr "Bu filament kullanılırken yazıcı başladığında eklenen G-kodu" msgid "Single Extruder Multi Material" msgstr "Tek ekstruder çoklu malzeme" @@ -17110,7 +17110,7 @@ msgid "This setting determines the maximum overhang angle that the branches of t msgstr "Bu ayar, ağaç desteğinin dallarının oluşmasına izin verilen maksimum çıkıntı açısını belirler. Açı artırılırsa, dallar daha yatay olarak basılabilir ve daha uzağa ulaşır." msgid "Preferred Branch Angle" -msgstr "Tercih Edilen Dal Açısı" +msgstr "Tercih edilen dal açısı" #. TRN PrintSettings: "Organic supports" > "Preferred Branch Angle" msgid "The preferred angle of the branches, when they do not have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster." @@ -17123,7 +17123,7 @@ msgid "This setting determines the distance between neighboring tree support nod msgstr "Bu ayar, komşu ağaç destek düğümleri arasındaki mesafeyi belirler." msgid "Branch Density" -msgstr "Dal Yoğunluğu" +msgstr "Dal yoğunluğu" #. TRN PrintSettings: "Organic supports" > "Branch Density" msgid "Adjusts the density of the support structure used to generate the tips of the branches. A higher value results in better overhangs but the supports are harder to remove, thus it is recommended to enable top support interfaces instead of a high branch density value if dense interfaces are needed." @@ -17142,7 +17142,7 @@ msgid "Distance from tree branch to the outermost brim line." msgstr "Ağaç dalından en dış kenar çizgisine kadar olan mesafe." msgid "Tip Diameter" -msgstr "Uç Çapı" +msgstr "Uç çapı" #. TRN PrintSettings: "Organic supports" > "Tip Diameter" msgid "Branch tip diameter for organic supports." @@ -17156,7 +17156,7 @@ msgstr "Bu ayar, destek düğümlerinin başlangıç çapını belirler." #. TRN PrintSettings: #lmFIXME msgid "Branch Diameter Angle" -msgstr "Dal Çapı Açısı" +msgstr "Dal çapı açısı" #. TRN PrintSettings: "Organic supports" > "Branch Diameter Angle" msgid "The angle of the branches' diameter as they gradually become thicker towards the bottom. An angle of 0 will cause the branches to have uniform thickness over their length. A bit of an angle can increase stability of the organic support." @@ -17184,13 +17184,13 @@ msgid "Support Ironing Pattern" msgstr "Destek ütüleme deseni" msgid "Support Ironing flow" -msgstr "Destek ütüleme akışı" +msgstr "Destek ütüleme akış oranı" msgid "The amount of material to extrude during ironing. Relative to flow of normal support interface layer height. Too high value results in overextrusion on the surface." msgstr "Ütüleme sırasında ekstrüde edilecek malzeme miktarı. Normal destek arayüzü katman yüksekliğinin akışına göre. Çok yüksek bir değer, yüzeyde aşırı ekstrüzyona neden olur." msgid "Support Ironing line spacing" -msgstr "Destek ütüleme satır aralığı" +msgstr "Destek ütüleme çizgi aralığı" msgid "Activate temperature control" msgstr "Sıcaklık kontrolünü etkinleştirin" @@ -17238,7 +17238,7 @@ msgid "Chamber minimal temperature" msgstr "Minimum bölme sıcaklığı" msgid "Nozzle temperature after the first layer" -msgstr "İlk katmandan sonraki katmanlar için nozul sıcaklığı." +msgstr "İlk katmandan sonraki nozul sıcaklığı" msgid "Detect thin walls" msgstr "İnce duvarı algıla" @@ -17344,7 +17344,7 @@ msgid "" msgstr "" "Geri çekilirken nozulun son yol boyunca ne kadar süre hareket edeceğini açıklayın.\n" "\n" -"Silme işleminin ne kadar sürdüğüne, ekstruder/filament geri çekme ayarlarının ne kadar hızlı ve uzun olduğuna bağlı olarak, kalan filamanı geri çekmek için bir geri çekme hareketine ihtiyaç duyulabilir.\n" +"Silme işleminin ne kadar sürdüğüne, ekstruder/filament geri çekme ayarlarının ne kadar hızlı ve uzun olduğuna bağlı olarak, kalan filamenti geri çekmek için bir geri çekme hareketine ihtiyaç duyulabilir.\n" "\n" "Aşağıdaki silme ayarından önce geri çekme miktarına bir değer ayarlamak, silme işleminden önce aşırı geri çekme işlemini gerçekleştirecektir, aksi takdirde silme işleminden sonra gerçekleştirilecektir." @@ -17355,7 +17355,7 @@ msgid "Internal ribs" msgstr "İç kaburgalar" msgid "Enable internal ribs to increase the stability of the prime tower." -msgstr "Ana kulenin stabilitesini artırmak için iç kaburgaları etkinleştirin." +msgstr "Hazırlık kulesinin (prime tower) stabilitesini ve mukavemetini artırmak için kulenin içerisine dikey kaburga (takviye) duvarları ekler." msgid "Purging volumes" msgstr "Hacimlerin temizlenmesi" @@ -17428,11 +17428,11 @@ msgid "" "\n" "For the wipe tower external perimeters the internal perimeter speed is used regardless of this setting." msgstr "" -"Silme kulesinde temizleme yaparken ve silme kulesi seyrek katmanlarını yazdırırken maksimum yazdırma hızı. Temizleme sırasında seyrek dolum hızı veya filamanın maksimum hacimsel hızından hesaplanan hız daha düşükse, bunun yerine en düşük olanı kullanılacaktır.\n" +"Silme kulesinde temizleme yaparken ve silme kulesi seyrek katmanlarını yazdırırken maksimum yazdırma hızı. Temizleme sırasında seyrek dolum hızı veya filamentin maksimum hacimsel hızından hesaplanan hız daha düşükse, bunun yerine en düşük olanı kullanılacaktır.\n" "\n" -"Seyrek katmanları yazdırırken iç çevre hızı veya filamanın maksimum hacimsel hızından hesaplanan hız daha düşükse bunun yerine en düşük olanı kullanılacaktır.\n" +"Seyrek katmanları yazdırırken iç çevre hızı veya filamentin maksimum hacimsel hızından hesaplanan hız daha düşükse bunun yerine en düşük olanı kullanılacaktır.\n" "\n" -"Bu hızın arttırılması kulenin stabilitesini etkileyebileceği gibi, nozülün silme kulesi üzerinde oluşmuş olabilecek damlacıklarla çarpışma kuvvetini de arttırabilir.\n" +"Bu hızın arttırılması kulenin stabilitesini etkileyebileceği gibi, nozulun silme kulesi üzerinde oluşmuş olabilecek damlacıklarla çarpışma kuvvetini de arttırabilir.\n" "\n" "Bu parametreyi varsayılan 90 mm/sn’nin üzerine çıkarmadan önce, yazıcınızın artan hızlarda güvenilir şekilde köprü kurabildiğinden ve takım değişimi iyi kontrol edildiğinde sızıntı yaptığından emin olun.\n" "\n" @@ -17459,16 +17459,16 @@ msgid "Rib" msgstr "Kaburga" msgid "Extra rib length" -msgstr "Ekstra rib uzunluğu" +msgstr "Ek kaburga uzunluğu" msgid "Positive values can increase the size of the rib wall, while negative values can reduce the size. However, the size of the rib wall can not be smaller than that determined by the cleaning volume." -msgstr "Pozitif değerler rib duvarının boyutunu artırabilirken, negatif değerler boyutunu azaltabilir. Ancak rib duvarının boyutu temizleme hacmi tarafından belirlenen boyuttan daha küçük olamaz." +msgstr "Ek kaburga (takviye) duvarının boyutunu ayarlar. Pozitif değerler kaburga duvarını büyütürken, negatif değerler küçültür. Ancak kaburga boyutu, temizleme hacmi (cleaning volume) ile belirlenen minimum sınırın altına inemez." msgid "Rib width" -msgstr "Rib genişliği" +msgstr "Kaburga genişliği" msgid "Rib width is always less than half the prime tower side length." -msgstr "Diş genişliği her zaman ana kule yan uzunluğunun yarısından azdır." +msgstr "Kaburga genişliği, her zaman hazırlık kulesinin (prime tower) kenar uzunluğunun yarısından az olmalıdır." msgid "Fillet wall" msgstr "Kavisli duvar" @@ -17522,7 +17522,7 @@ msgid "Maximal bridging distance" msgstr "Maksimum köprüleme mesafesi" msgid "Maximal distance between supports on sparse infill sections." -msgstr "Bu nesne, filamentten tasarruf etmek ve baskı süresini azaltmak için bir filament değişiminden sonra nozulu temizlemek için kullanılacaktır. Sonuç olarak nesnelerin renkleri karıştırılacaktır. Prime tower etkinleştirilmediği sürece etkili olmayacaktır." +msgstr "Seyrek dolgu bölümlerindeki destekler arası maksimum mesafe." msgid "Wipe tower purge lines spacing" msgstr "Silme kulesi temizleme hatları aralığı" @@ -17764,7 +17764,7 @@ msgid "Temperature delta applied during pre-heating before tool change." msgstr "Takım değişiminden önce ön ısıtma sırasında uygulanan sıcaklık farkı." msgid "Detect narrow internal solid infills" -msgstr "Dar iç katı dolguyu tespit et" +msgstr "Dar iç dolguları tespit et" msgid "This option will auto-detect narrow internal solid infill areas. If enabled, the concentric pattern will be used for the area to speed up printing. Otherwise, the rectilinear pattern will be used by default." msgstr "Bu seçenek dar dahili katı dolgu alanını otomatik olarak algılayacaktır. Etkinleştirilirse, yazdırmayı hızlandırmak amacıyla alanda eşmerkezli desen kullanılacaktır. Aksi takdirde varsayılan olarak doğrusal desen kullanılır." @@ -17795,7 +17795,7 @@ msgid "Export slicing data" msgstr "Dilimleme verilerini dışa aktar" msgid "Export slicing data to a folder" -msgstr "Dilimleme verilerini bir klasöre aktarın." +msgstr "Dilimleme verilerini bir klasöre dışa aktar" msgid "Load slicing data" msgstr "Dilimleme verilerini yükle" @@ -17843,13 +17843,13 @@ msgid "mtcpp" msgstr "mtcpp" msgid "max triangle count per plate for slicing" -msgstr "dilimleme için plaka başına maksimum üçgen sayısı." +msgstr "dilimleme için tabla başına maksimum üçgen sayısı" msgid "mstpp" msgstr "mstpp" msgid "max slicing time per plate in seconds" -msgstr "saniye cinsinden plaka başına maksimum dilimleme süresi." +msgstr "tabla başına saniye cinsinden maksimum dilimleme süresi" msgid "No check" msgstr "Kontrol yok" @@ -17960,7 +17960,7 @@ msgid "Load uptodate process/machine settings when using uptodate" msgstr "Güncel olan bir baskı süreci (process) veya makine (printer) profili seçildiğinde, ona ait en güncel ayarları otomatik olarak yükle" msgid "load up-to-date process/machine settings from the specified file when using up-to-date" -msgstr "Güncellemeyi kullanırken belirtilen dosyadan güncel işlem/yazıcı ayarlarını yükle." +msgstr "güncel durumdayken belirtilen dosyadan güncel proses/makine ayarlarını yükle" msgid "Load uptodate filament settings when using uptodate" msgstr "Güncel olan bir filament profili kullanırken, onun en güncel ayarlarını yükle" @@ -18068,13 +18068,13 @@ msgid "MakerLab version to generate this 3MF." msgstr "Bu 3mf’yi oluşturmak için MakerLab sürümü." msgid "Metadata name list" -msgstr "meta veri adı listesi" +msgstr "Meta veri adı listesi" msgid "Metadata name list added into 3MF." msgstr "3mf’ye meta veri adı listesi eklendi." msgid "Metadata value list" -msgstr "meta veri değer listesi" +msgstr "Meta veri değeri listesi" msgid "Metadata value list added into 3MF." msgstr "3mf’ye meta veri değeri listesi eklendi." @@ -18131,7 +18131,7 @@ msgid "Initial extruder" msgstr "İlk ekstruder" msgid "Zero-based index of the first extruder used in the print. Same as initial_tool." -msgstr "Baskıda kullanılan ilk ekstruderin sıfır bazlı indeksi. başlangıç_aracı ile aynı." +msgstr "Baskıda kullanılan ilk ekstruderin sıfır bazlı indeksi. initial_tool ile aynı." msgid "Initial tool" msgstr "Başlangıç aracı" @@ -18179,13 +18179,13 @@ msgid "Weight per extruder" msgstr "Ekstruder başına ağırlık" msgid "Weight per extruder extruded during the entire print. Calculated from filament_density value in Filament Settings." -msgstr "Baskının tamamı boyunca ekstrüzyon yapılan ekstruder başına ağırlık. Filament Ayarlarındaki filaman yoğunluğu değerinden hesaplanır." +msgstr "Baskının tamamı boyunca ekstrüzyon yapılan ekstruder başına ağırlık. Filament Ayarlarındaki filament yoğunluğu değerinden hesaplanır." msgid "Total weight" msgstr "Toplam ağırlık" msgid "Total weight of the print. Calculated from filament_density value in Filament Settings." -msgstr "Baskının toplam ağırlığı. Filament Ayarlarındaki filaman yoğunluğu değerinden hesaplanır." +msgstr "Baskının toplam ağırlığı. Filament Ayarlarındaki filament yoğunluğu değerinden hesaplanır." msgid "Total layer count" msgstr "Toplam katman sayısı" @@ -18221,7 +18221,7 @@ msgid "Wipe tower volume" msgstr "Kule hacmini sil" msgid "Total filament volume extruded on the wipe tower." -msgstr "Silme kulesinde ekstrüzyona tabi tutulan toplam filaman hacmi." +msgstr "Silme kulesinde ekstrüzyona tabi tutulan toplam filament hacmi." msgid "Used filament" msgstr "Kullanılan" @@ -18239,7 +18239,7 @@ msgid "Filament length (meters)" msgstr "Filament uzunluğu (metre)" msgid "Total filament length used in meters. Replaced with actual value during post-processing." -msgstr "Metre cinsinden kullanılan toplam filaman uzunluğu. Son işlem sırasında gerçek değerle değiştirilir." +msgstr "Metre cinsinden kullanılan toplam filament uzunluğu. Son işlem sırasında gerçek değerle değiştirilir." msgid "Number of objects" msgstr "Nesne sayısı" @@ -18434,7 +18434,7 @@ msgid "Meshing of a model file failed or no valid shape." msgstr "Bir model dosyasının meshlenmesi başarısız oldu veya geçerli bir şekil yok." msgid "The supplied file couldn't be read because it's empty." -msgstr "Sağlanan dosya boş olduğundan okunamadı" +msgstr "Seçilen dosya boş olduğundan okunamıyor." msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Bilinmeyen dosya formatı. Giriş dosyası .stl, .obj, .amf(.xml) uzantılı olmalıdır." @@ -18581,7 +18581,7 @@ msgid "" "Within the same extruder, the name(%s) must be unique when the filament type, nozzle diameter, and nozzle flow are the same.\n" "Are you sure you want to override the historical result?" msgstr "" -"Aynı ekstruder içinde filament tipi, nozül çapı ve nozül akışı aynı olduğunda adın(%s) benzersiz olması gerekir.\n" +"Aynı ekstruder içinde filament tipi, nozul çapı ve nozul akışı aynı olduğunda adın(%s) benzersiz olması gerekir.\n" "Geçmiş sonucu geçersiz kılmak istediğinizden emin misiniz?" #, c-format, boost-format @@ -18807,7 +18807,7 @@ msgid "Nozzle Flow" msgstr "Nozul Akışı" msgid "Filament position" -msgstr "filament konumu" +msgstr "Filament konumu" msgid "Filament For Calibration" msgstr "Kalibrasyon İçin Filament" @@ -18842,7 +18842,7 @@ msgid "Sync AMS and nozzle information" msgstr "AMS ve püskürtme ucu bilgilerini senkronize edin" msgid "Calibration only supports cases where the left and right nozzle diameters are identical." -msgstr "Kalibrasyon yalnızca sol ve sağ meme çaplarının aynı olduğu durumları destekler." +msgstr "Kalibrasyon yalnızca sol ve sağ nozul çaplarının aynı olduğu durumları destekler." msgid "From k Value" msgstr "K değerinden" @@ -18897,7 +18897,7 @@ msgstr "Akış Dinamiği Kalibrasyonunu Düzenle" #, c-format, boost-format msgid "Within the same extruder, the name '%s' must be unique when the filament type, nozzle diameter, and nozzle flow are identical. Please choose a different name." -msgstr "Aynı ekstruder içinde, filaman tipi, nozül çapı ve nozül akışı aynı olduğunda '%s' adı benzersiz olmalıdır. Lütfen farklı bir ad seçin." +msgstr "Aynı ekstruder içinde, filament tipi, bozul çapı ve nozul akışı aynı olduğunda '%s' adı benzersiz olmalıdır. Lütfen farklı bir ad seçin." msgid "New Flow Dynamic Calibration" msgstr "Yeni Akış Dinamik Kalibrasyonu" @@ -18909,7 +18909,7 @@ msgid "The extruder must be selected." msgstr "Ekstruder seçilmelidir." msgid "The nozzle must be selected." -msgstr "Meme seçilmelidir." +msgstr "Nozul seçilmelidir." msgid "Network lookup" msgstr "Ağ araması" @@ -19204,7 +19204,7 @@ msgstr "" "Desteklenen şekillendirici türleri için ürün yazılımı belgelerinize bakın." msgid "Frequency (Start / End): " -msgstr "Frekans (Başlangıç ​​/ Bitiş):" +msgstr "Frekans (Başlangıç / Bitiş): " msgid "Start / End" msgstr "Başlangıç / Bitiş" @@ -19243,7 +19243,7 @@ msgid "Check firmware compatibility." msgstr "Firmware uyumluluğunu kontrol edin." msgid "Frequency: " -msgstr "Sıklık:" +msgstr "Frekans: " # AI Translated msgid "Damp" @@ -19272,10 +19272,10 @@ msgid "SCV-V2" msgstr "SCV-V2" msgid "Start: " -msgstr "Başlangıç:" +msgstr "Başlat: " msgid "End: " -msgstr "Son:" +msgstr "Son: " msgid "Cornering settings" msgstr "Viraj alma ayarları" @@ -19517,7 +19517,7 @@ msgid "Subtract with" msgstr "Şununla çıkar" msgid "selected" -msgstr "Seçili" +msgstr "seçildi" msgid "Part 1" msgstr "Bölüm 1" @@ -19705,7 +19705,7 @@ msgid "Input Custom Nozzle Diameter" msgstr "Özel Nozul Çapını Girin" msgid "Can't find my nozzle diameter" -msgstr "Meme çapımı bulamıyorum" +msgstr "Nozul çapımı bulamıyorum" msgid "Printable Space" msgstr "Yazdırılabilir Alan" @@ -19761,7 +19761,7 @@ msgid "" "\tCancel: Do not create a preset; return to the creation interface." msgstr "" "Oluşturduğunuz yazıcı ön ayarının zaten aynı ada sahip bir ön ayarı var. Üzerine yazmak istiyor musunuz?\n" -"\tEvet: Aynı adı taşıyan yazıcı ön ayarının üzerine yazın; aynı ön ayar adı taşıyan filaman ve proses ön ayarları yeniden oluşturulacak ve aynı ön ayar \n" +"\tEvet: Aynı adı taşıyan yazıcı ön ayarının üzerine yazın; aynı ön ayar adı taşıyan filament ve proses ön ayarları yeniden oluşturulacak ve aynı ön ayar \n" "adı olmayan filament ve işlem ön ayarları rezerve edilecektir.\n" "\tİptal: Ön ayar oluşturmayın, oluşturma arayüzüne dönün." @@ -19799,7 +19799,7 @@ msgid "You have not yet selected the printer to replace the nozzle for; please c msgstr "Hala nozulu değiştirmek için yazıcı seçmediniz, lütfen bir seçim yapın." msgid "The entered nozzle diameter is invalid, please re-enter:\n" -msgstr "Girilen meme çapı geçersiz, lütfen tekrar girin:\n" +msgstr "Girilen nozul çapı geçersiz, lütfen tekrar girin:\n" msgid "" "The system preset does not allow creation. \n" @@ -19889,10 +19889,10 @@ msgid "add bundle structure file fail" msgstr "paket yapısı dosyası ekle başarısız" msgid "finalize fail" -msgstr "Tamamlama başarısız" +msgstr "tamamlama başarısız oldu" msgid "open zip written fail" -msgstr "ZIP dosyasını açma başarısız" +msgstr "zip dosyası açılamadı" msgid "Export successful" msgstr "Dışa aktarma başarılı" @@ -19993,7 +19993,7 @@ msgid "" "All the filament presets belong to this filament would be deleted.\n" "If you are using this filament on your printer, please reset the filament information for that slot." msgstr "" -"Bu filamente ait tüm filaman ön ayarları silinecektir.\n" +"Bu filamente ait tüm filament ön ayarları silinecektir.\n" "Yazıcınızda bu filamenti kullanıyorsanız lütfen o yuvanın filament bilgisini sıfırlayın." msgid "Delete filament" @@ -20058,14 +20058,14 @@ msgstr "Yazıcı ekstrüderlerinin sayısı ve kalibrasyon için seçilen yazıc #, c-format, boost-format msgid "The nozzle diameter of %s extruder is 0.2mm which does not support automatic Flow Dynamics calibration." -msgstr "%s ekstruderin meme çapı 0,2 mm'dir ve bu, otomatik Akış Dinamiği kalibrasyonunu desteklemez." +msgstr "%s ekstruderin nozul çapı 0,2 mm'dir ve bu, otomatik Akış Dinamiği kalibrasyonunu desteklemez." #, c-format, boost-format msgid "" "The currently selected nozzle diameter of %s extruder does not match the actual nozzle diameter.\n" "Please click the Sync button above and restart the calibration." msgstr "" -"%s ekstruderin şu anda seçili olan meme çapı, gerçek meme çapıyla eşleşmiyor.\n" +"%s ekstruderin şu anda seçili olan nozul çapı, gerçek nozul çapıyla eşleşmiyor.\n" "Lütfen yukarıdaki Senkronizasyon düğmesine tıklayın ve kalibrasyonu yeniden başlatın." msgid "" @@ -20507,7 +20507,7 @@ msgid "It has a small layer height. This results in almost negligible layer line msgstr "Küçük bir katman yüksekliğine sahiptir ve neredeyse ihmal edilebilir katman çizgileri ve yüksek baskı kalitesi sağlar. Çoğu genel yazdırma durumu için uygundur." msgid "Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in much higher print quality but a much longer print time." -msgstr "0,2 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha düşük hız ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun baskı süresi elde edilir." +msgstr "0,2 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha düşük hız ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun baskı süresi elde edilir." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height. This results in almost negligible layer lines and slightly shorter print time." msgstr "0,2 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, biraz daha büyük katman yüksekliğine sahiptir ve neredeyse ihmal edilebilir düzeyde katman çizgileri ve biraz daha kısa yazdırma süresi sağlar." @@ -20531,7 +20531,7 @@ msgid "It has a normal layer height. This results in average layer lines and pri msgstr "Genel bir katman yüksekliğine sahiptir ve genel katman çizgileri ve baskı kalitesiyle sonuçlanır. Çoğu genel yazdırma durumu için uygundur." msgid "Compared with the default profile of a 0.4 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filaman tüketimine ve daha uzun baskı süresine neden olur." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filament tüketimine ve daha uzun baskı süresine neden olur." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but slightly shorter print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha büyük bir katman yüksekliğine sahiptir ve daha belirgin katman çizgileri ve daha düşük baskı kalitesi sağlar, ancak biraz daha kısa yazdırma süresi sağlar." @@ -20543,13 +20543,13 @@ msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller la msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha küçük bir katman yüksekliğine sahiptir ve daha az görünür katman çizgileri ve daha yüksek baskı kalitesi sağlar, ancak daha uzun yazdırma süresi sağlar." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in less apparent layer lines and much higher print quality but much longer print time." -msgstr "0,4 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece daha az belirgin katman çizgileri ve çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun yazdırma süresi elde edilir." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece daha az belirgin katman çizgileri ve çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun yazdırma süresi elde edilir." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and higher print quality but longer print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, katman yüksekliği daha küçüktür ve neredeyse göz ardı edilebilir katman çizgileri ve daha yüksek baskı kalitesi sağlar, ancak daha uzun yazdırma süresi sağlar." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost negligible layer lines and much higher print quality but much longer print time." -msgstr "0,4 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece, neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve çok daha yüksek baskı kalitesi elde edilirken, çok daha uzun baskı süresi elde edilir." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece, neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve çok daha yüksek baskı kalitesi elde edilirken, çok daha uzun baskı süresi elde edilir." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and longer print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, katman yüksekliği daha küçüktür ve neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve daha uzun yazdırma süresi sağlar." @@ -20558,7 +20558,7 @@ msgid "It has a big layer height. This results in apparent layer lines and ordin msgstr "Büyük bir katman yüksekliğine sahiptir ve belirgin katman çizgileri ile sıradan baskı kalitesi ve baskı süresi sağlar." msgid "Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "0,6 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filaman tüketimine ve daha uzun baskı süresine neden olur." +msgstr "0,6 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filament tüketimine ve daha uzun baskı süresine neden olur." msgid "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but shorter print time in some cases." msgstr "0,6 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha büyük bir katman yüksekliğine sahiptir ve daha belirgin katman çizgileri ve daha düşük baskı kalitesi sağlar, ancak bazı yazdırma durumlarında daha kısa yazdırma süresi sağlar." @@ -20591,16 +20591,16 @@ msgid "This is neither a commonly used filament, nor one of Bambu filaments, and msgstr "Bu ne yaygın olarak kullanılan bir filament ne de Bambu filamentlerinden biri ve markadan markaya çok değişiyor. Bu nedenle, yazdırmadan önce satıcınızdan uygun profili sormanız ve bazı parametreleri performansına göre ayarlamanız önemle tavsiye edilir." msgid "When printing this filament, there's a risk of warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials." -msgstr "Bu filamanı yazdırırken eğrilme ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." +msgstr "Bu filamenti yazdırırken eğrilme ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." msgid "When printing this filament, there's a risk of nozzle clogging, oozing, warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials." -msgstr "Bu filamanı yazdırırken nozulun tıkanması, sızması, eğrilmesi ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." +msgstr "Bu filamenti yazdırırken nozulun tıkanması, sızması, eğrilmesi ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." msgid "To get better transparent or translucent results with the corresponding filament, please refer to this wiki: Printing tips for transparent PETG." msgstr "İlgili filamentle daha iyi şeffaf veya yarı şeffaf sonuçlar elde etmek için lütfen şu wiki'ye bakın: Şeffaf PETG için yazdırma ipuçları." msgid "To make the prints get higher gloss, please dry the filament before use, and set the outer wall speed to be 40 to 60 mm/s when slicing." -msgstr "Baskıların daha parlak olmasını sağlamak için lütfen kullanmadan önce filamanı kurutun ve dilimleme sırasında dış duvar hızını 40 ila 60 mm/s olarak ayarlayın." +msgstr "Baskıların daha parlak olmasını sağlamak için lütfen kullanmadan önce filamenti kurutun ve dilimleme sırasında dış duvar hızını 40 ila 60 mm/s olarak ayarlayın." msgid "This filament is only used to print models with a low density usually, and some special parameters are required. To get better printing quality, please refer to this wiki: Instructions for printing RC model with foaming PLA (PLA Aero)." msgstr "Bu filament genellikle yalnızca düşük yoğunluklu modelleri basmak için kullanılır ve bazı özel parametreler gereklidir. Daha iyi baskı kalitesi elde etmek için lütfen bu wiki'ye bakın: RC modelini köpüklü PLA (PLA Aero) ile yazdırma talimatları." @@ -20609,7 +20609,7 @@ msgid "This filament is only used to print models with a low density usually, an msgstr "Bu filament genellikle yalnızca düşük yoğunluklu modelleri basmak için kullanılır ve bazı özel parametreler gereklidir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: ASA Aero Printing Guide." msgid "This filament is too soft and not compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide." -msgstr "Bu filaman çok yumuşak ve AMS ile uyumlu değil. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." +msgstr "Bu filament çok yumuşak ve AMS ile uyumlu değil. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." msgid "This filament has high enough hardness (about 67D) and is compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide." msgstr "Bu filament yeterince yüksek sertliğe sahiptir (yaklaşık 67D) ve AMS ile uyumludur. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." @@ -20618,7 +20618,7 @@ msgid "If you are to print a kind of soft TPU, please don't slice with this prof msgstr "Bir tür yumuşak TPU yazdıracaksanız lütfen bu profille kesmeyin; bu yalnızca yeterince yüksek sertliğe sahip (55D'den az olmayan) ve AMS ile uyumlu TPU içindir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." msgid "This is a water-soluble support filament, and usually it is only for the support structure and not for the model body. Printing this filament is of many requirements, and to get better printing quality, please refer to this wiki: PVA Printing Guide." -msgstr "Bu suda çözünebilen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Bu filamanı yazdırmak birçok gereksinimi gerektirir ve daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: PVA Yazdırma Kılavuzu." +msgstr "Bu suda çözünebilen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Bu filamenti yazdırmak birçok gereksinimi gerektirir ve daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: PVA Yazdırma Kılavuzu." msgid "This is a non-water-soluble support filament, and usually it is only for the support structure and not for the model body. To get better printing quality, please refer to this wiki: Printing Tips for Support Filament and Support Function." msgstr "Bu suda çözünmeyen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: Destek Filamenti ve Destek Fonksiyonu için Yazdırma İpuçları." @@ -20654,7 +20654,7 @@ msgid "High quality profile for 0.8mm nozzle, prioritizing print quality." msgstr "0,8 mm püskürtme ucu için baskı kalitesini ön planda tutan yüksek kaliteli profil." msgid "Strength profile for 0.8mm nozzle, prioritizing strength." -msgstr "0,8 mm'lik nozül için güç profili, dayanıklılığa öncelik verilir." +msgstr "0,8 mm'lik nozul için güç profili, dayanıklılığa öncelik verilir." msgid "Standard profile for 0.8mm nozzle, prioritizing speed." msgstr "Hıza öncelik veren 0,8 mm nozul için standart profil." @@ -20814,13 +20814,13 @@ msgid "Custom Mode" msgstr "Özel Mod" msgid "Generates filament grouping for the left and right nozzles based on the most filament-saving principles to minimize waste." -msgstr "Atıkları en aza indirmek için en fazla filaman tasarrufu sağlayan ilkelere dayalı olarak sol ve sağ püskürtme uçları için filaman gruplandırması oluşturur." +msgstr "Atıkları en aza indirmek için en fazla filament tasarrufu sağlayan ilkelere dayalı olarak sol ve sağ püskürtme uçları için filament gruplandırması oluşturur." msgid "Generates filament grouping for the left and right nozzles based on the printer's actual filament status, reducing the need for manual filament adjustment." -msgstr "Yazıcının gerçek filaman durumuna göre sol ve sağ püskürtme uçları için filaman gruplandırması oluşturarak manuel filaman ayarlaması ihtiyacını azaltır." +msgstr "Yazıcının gerçek filament durumuna göre sol ve sağ püskürtme uçları için filament gruplandırması oluşturarak manuel filament ayarlaması ihtiyacını azaltır." msgid "Manually assign filament to the left or right nozzle" -msgstr "Filamenti manuel olarak sol veya sağ memeye atayın" +msgstr "Filamenti manuel olarak sol veya sağ nozule atayın" msgid "Global settings" msgstr "Genel ayarlar" @@ -20855,7 +20855,7 @@ msgid "Set the physical nozzle count..." msgstr "Fiziksel nozul sayısını ayarlayın..." msgid "The filament grouping method for current plate is determined by the dropdown option at the slicing plate button." -msgstr "Geçerli plaka için filaman gruplandırma yöntemi, dilimleme plakası düğmesindeki açılır seçenekle belirlenir." +msgstr "Geçerli plaka için filament gruplandırma yöntemi, dilimleme plakası düğmesindeki açılır seçenekle belirlenir." msgid "Connected to Obico successfully!" msgstr "Obico'ya başarıyla bağlanıldı!" @@ -21552,10 +21552,10 @@ msgid "The filament model is unknown. Generic filament presets will be used." msgstr "Filament modeli bilinmiyor. Genel filament ön ayarları kullanılacaktır." msgid "The filament may not be compatible with the current machine settings. A random filament preset will be used." -msgstr "Filament mevcut makine ayarlarıyla uyumlu olmayabilir. Rastgele bir filaman ön ayarı kullanılacaktır." +msgstr "Filament mevcut makine ayarlarıyla uyumlu olmayabilir. Rastgele bir filament ön ayarı kullanılacaktır." msgid "The filament model is unknown. A random filament preset will be used." -msgstr "Filament modeli bilinmiyor. Rastgele bir filaman ön ayarı kullanılacaktır." +msgstr "Filament modeli bilinmiyor. Rastgele bir filament ön ayarı kullanılacaktır." #: resources/data/hints.ini: [hint:Precise wall] msgid "" @@ -21768,8 +21768,7 @@ msgstr "" "Baskılarınızı plakalara ayırın\n" "Çok sayıda parçası olan bir modeli baskıya hazır ayrı kalıplara bölebileceğinizi biliyor muydunuz? Bu, tüm parçaları takip etme sürecini basitleştirecektir." -#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer -#: Height] +#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height] msgid "" "Speed up your print with Adaptive Layer Height\n" "Did you know that you can print a model even faster by using the Adaptive Layer Height option? Check it out!" @@ -21842,8 +21841,7 @@ msgstr "" "Gücü artırın\n" "Modelin gücünü artırmak için daha fazla duvar halkası ve daha yüksek seyrek dolgu yoğunluğu kullanabileceğinizi biliyor muydunuz?" -#: resources/data/hints.ini: [hint:When do you need to print with the printer -#: door opened] +#: resources/data/hints.ini: [hint:When do you need to print with the printer door opened] msgid "" "When do you need to print with the printer door opened?\n" "Did you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature? There is more info about this in the Wiki." @@ -21905,10 +21903,10 @@ msgstr "" #~ msgstr "Daha Sonra Yeniden Başlat" #~ msgid "Select filament that installed to the left nozzle" -#~ msgstr "Sol nozüle takılan filamanı seçin" +#~ msgstr "Sol nozule takılan filamenti seçin" #~ msgid "Select filament that installed to the right nozzle" -#~ msgstr "Sağ nozüle takılan filamanı seçin" +#~ msgstr "Sağ nozule takılan filamenti seçin" #, c-format, boost-format #~ msgid "Note: the filament type(%s) does not match with the filament type(%s) in the slicing file. If you want to use this slot, you can install %s instead of %s and change slot information on the 'Device' page." @@ -21919,7 +21917,7 @@ msgstr "" #~ msgstr "Not: yuva boş veya tanımsız. Bu yuvayı kullanmak istiyorsanız 'Cihaz' sayfasından %s yükleyebilir ve yuva bilgilerini değiştirebilirsiniz." #~ msgid "Note: Only filament-loaded slots can be selected." -#~ msgstr "Not: Yalnızca filaman yüklü yuvalar seçilebilir." +#~ msgstr "Not: Yalnızca filament yüklü yuvalar seçilebilir." #~ msgid "Save the printing files initiated from Bambu Studio, Bambu Handy and MakerWorld on External Storage" #~ msgstr "Bambu Studio, Bambu Handy ve MakerWorld'den başlatılan yazdırma dosyalarını Harici Depolamaya kaydedin" @@ -22244,7 +22242,7 @@ msgstr "" #~ msgstr "hafızaya alınan meme boyutu: %d" #~ msgid "The size of nozzle type in preset is not consistent with memorized nozzle. Did you change your nozzle lately?" -#~ msgstr "Ön ayardaki nozül tipinin boyutu hafızaya alınan nozül ile tutarlı değil. Son zamanlarda nozulunuzu değiştirdiniz mi?" +#~ msgstr "Ön ayardaki nozul tipinin boyutu hafızaya alınan nozul ile tutarlı değil. Son zamanlarda nozulunuzu değiştirdiniz mi?" #, c-format, boost-format #~ msgid "nozzle[%d] in preset: %.1f" @@ -22380,7 +22378,7 @@ msgstr "" #~ msgstr "Sol püskürtme ucu: %smm" #~ msgid "Right nozzle: %smm" -#~ msgstr "Sağ nozül: %smm" +#~ msgstr "Sağ nozul: %smm" #~ msgid "\"Fix Model\" feature is currently only on Windows. Please repair the model on Orca Slicer(windows) or CAD softwares." #~ msgstr "\"Modeli Onar\" özelliği şu anda yalnızca Windows'ta bulunmaktadır. Lütfen modeli Orca Slicer (windows) veya CAD yazılımlarında onarın." From fb36d5e73b8fa662ccf6b918581bda414bb53187 Mon Sep 17 00:00:00 2001 From: Valerii Bokhan <80919135+valerii-bokhan@users.noreply.github.com> Date: Sat, 1 Aug 2026 22:58:04 +0200 Subject: [PATCH 06/23] Feature: Smooth Factor for the Hilbert Curve sparse infill (#14969) --- src/libslic3r/Fill/Fill.cpp | 12 ++ src/libslic3r/Fill/FillBase.hpp | 3 + src/libslic3r/Fill/FillPlanePath.cpp | 163 +++++++++++++++++++++- src/libslic3r/Fill/FillPlanePath.hpp | 7 + src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 12 ++ src/libslic3r/PrintConfig.hpp | 1 + src/libslic3r/PrintObject.cpp | 1 + src/slic3r/GUI/ConfigManipulation.cpp | 1 + src/slic3r/GUI/GUI_Factories.cpp | 1 + src/slic3r/GUI/Tab.cpp | 1 + tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_fill_plane_path.cpp | 164 +++++++++++++++++++++++ 13 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 tests/libslic3r/test_fill_plane_path.cpp diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index f29d4ef3fd..88d87ddb26 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -278,6 +278,9 @@ struct SurfaceFillParams // For Gyroid: when true, use the parameterized "optimized" wave. bool gyroid_optimized = false; + // Orca: corner smoothing factor in the range [0, 1]. + double smooth_factor { 0. }; + CenterOfSurfacePattern center_of_surface_pattern{CenterOfSurfacePattern::Each_Surface}; bool separated_infills{false}; @@ -316,6 +319,7 @@ struct SurfaceFillParams RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle); RETURN_COMPARE_NON_EQUAL(gyroid_optimized); + RETURN_COMPARE_NON_EQUAL(smooth_factor); RETURN_COMPARE_NON_EQUAL(center_of_surface_pattern); RETURN_COMPARE_NON_EQUAL(separated_infills); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, fill_order); @@ -348,6 +352,7 @@ struct SurfaceFillParams this->center_of_surface_pattern == rhs.center_of_surface_pattern && this->separated_infills == rhs.separated_infills && this->gyroid_optimized == rhs.gyroid_optimized && + this->smooth_factor == rhs.smooth_factor && this->fill_order == rhs.fill_order; } }; @@ -964,6 +969,11 @@ std::vector group_fills(const Layer &layer, LockRegionParam &lock_p params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value, region_config.sparse_infill_rotate_template.value); params.fixed_angle = !region_config.sparse_infill_rotate_template.value.empty(); + + // Orca: special case; apply smoothing factor only for Hilbert Curve sparse infill. + // FillHilbertCurve::generate clamps and validates the value itself. + if (params.pattern == ipHilbertCurve) + params.smooth_factor = 0.01 * region_config.sparse_infill_smooth_factor.value; } else { const bool top_layer_direction_set = surface.is_top() && region_config.top_layer_direction.value >= 0.; const bool bottom_layer_direction_set = surface.is_bottom() && region_config.bottom_layer_direction.value >= 0.; @@ -1328,6 +1338,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.lateral_lattice_angle_2 = surface_fill.params.lateral_lattice_angle_2; params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.gyroid_optimized = surface_fill.params.gyroid_optimized; + params.smooth_factor = surface_fill.params.smooth_factor; // BBS params.flow = surface_fill.params.flow; @@ -1569,6 +1580,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.multiline = surface_fill.params.multiline; params.gyroid_optimized = surface_fill.params.gyroid_optimized; + params.smooth_factor = surface_fill.params.smooth_factor; for (ExPolygon &expoly : surface_fill.expolygons) { // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 8128b9c9d1..d50c29b332 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -82,6 +82,9 @@ struct FillParams // For Gyroid: when true, use the parameterized "optimized" variant. bool gyroid_optimized { false }; + // Orca: corner smoothing factor in the range [0, 1]. + double smooth_factor { 0. }; + // For Lateral lattice coordf_t lateral_lattice_angle_1 { 0.f }; coordf_t lateral_lattice_angle_2 { 0.f }; diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 7ce8e4abb3..7c4f285ac6 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -114,12 +114,12 @@ void FillPlanePath::_fill_surface_single( // Filling in a bounding box over the whole object, clip generated polyline against the snug bounding box. snug_bounding_box.translate(-shift.x(), -shift.y()); InfillPolylineClipper output(snug_bounding_box, distance_between_lines); - this->generate(min_x, min_y, max_x, max_y, resolution, output); + this->generate(min_x, min_y, max_x, max_y, resolution, params, output); polyline.points = std::move(output.result()); } else { // Filling in a snug bounding box, no need to clip. InfillPolylineOutput output(distance_between_lines); - this->generate(min_x, min_y, max_x, max_y, resolution, output); + this->generate(min_x, min_y, max_x, max_y, resolution, params, output); polyline.points = std::move(output.result()); } } @@ -288,6 +288,147 @@ static void generate_hilbert_curve(coord_t min_x, coord_t min_y, coord_t max_x, } } +using QuinticBezier = std::array; + +static bool is_bezier_flat(const QuinticBezier &curve, const double deviation) +{ + // A Bezier curve stays inside the convex hull of its control points. Therefore, keeping every + // control point within a deviation-wide strip around the endpoint chord conservatively bounds the + // flattening error. The cross product is the perpendicular distance scaled by the chord length; + // comparing squared values avoids a square root. + const Vec2d chord = curve.back() - curve.front(); + const double chord_length_sq = chord.squaredNorm(); + const double max_cross_sq = deviation * deviation * chord_length_sq; + + for (size_t i = 1; i + 1 < curve.size(); ++i) { + const Vec2d offset = curve[i] - curve.front(); + const double cross = chord.x() * offset.y() - chord.y() * offset.x(); + if (cross * cross > max_cross_sq) + return false; + } + return true; +} + +static void subdivide_bezier(const QuinticBezier &curve, QuinticBezier &left, QuinticBezier &right) +{ + // Split the curve at t = 0.5 using de Casteljau's algorithm. Each averaging level contributes one + // control point to the left half and one to the right half; the latter is filled backwards to keep + // both resulting control polygons in their original parameter direction. + QuinticBezier subdivision = curve; + left.front() = subdivision.front(); + right.back() = subdivision.back(); + for (size_t level = 1; level < curve.size(); ++level) { + for (size_t i = 0; i + level < curve.size(); ++i) + subdivision[i] = 0.5 * (subdivision[i] + subdivision[i + 1]); + left[level] = subdivision.front(); + right[curve.size() - level - 1] = subdivision[curve.size() - level - 1]; + } +} + +static void flatten_bezier(const QuinticBezier &curve, const double deviation, std::vector &output) +{ + // Subdivide to at least depth 1 so a rounded corner cannot collapse to a single diagonal chord. + // A uniform subdivision depth keeps samples at equal parameter intervals t = k / 2^depth, + // avoiding abrupt segment-length jumps at adaptive-depth boundaries. + static constexpr size_t max_depth = 16; + + std::vector subcurves(2); + subdivide_bezier(curve, subcurves[0], subcurves[1]); + + for (size_t depth = 1; depth < max_depth; ++depth) { + bool all_flat = true; + for (const QuinticBezier &c : subcurves) + if (!is_bezier_flat(c, deviation)) { + all_flat = false; + break; + } + if (all_flat) + break; + std::vector finer(subcurves.size() * 2); + for (size_t i = 0; i < subcurves.size(); ++i) + subdivide_bezier(subcurves[i], finer[i * 2], finer[i * 2 + 1]); + subcurves = std::move(finer); + } + + // The curve start is deliberately omitted so consecutive curve pieces can share it without duplication. + output.reserve(output.size() + subcurves.size()); + for (const QuinticBezier &c : subcurves) + output.emplace_back(c.back()); +} + +template +static void generate_smooth_hilbert_curve( + coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const double corner_distance, Output &output) +{ + // A Hilbert curve is defined on a square grid whose side is a power of two. As in the unsmoothed + // generator, expand the larger requested dimension to the next valid Hilbert grid size. The output + // clipper or the later region intersection removes the padded part of the traversal. + size_t sz = 2; + const size_t sz0 = std::max(max_x + 1 - min_x, max_y + 1 - min_y); + while (sz < sz0) + sz <<= 1; + + const size_t point_count = sz * sz; + output.reserve(point_count); + + // The caller normalizes resolution to the unit Hilbert grid; retain a finite positive tolerance + // if this helper is invoked with an invalid resolution. + const double deviation = resolution > 0. && std::isfinite(resolution) ? resolution : EPSILON; + // Construct one canonical 90-degree corner from (-corner_distance, 0) to (0, corner_distance). + // At each end, the first three control points are collinear and equally spaced: the tangent follows + // the adjoining straight leg and the second derivative is zero. The endpoint curvature is therefore + // zero, giving G2 joins to both legs. Every Hilbert turn is an oriented copy of this curve, so flatten + // it only once to the requested chordal-deviation tolerance. + const QuinticBezier corner_curve {{ + {-corner_distance, 0.}, {-0.7 * corner_distance, 0.}, {-0.4 * corner_distance, 0.}, + {0., 0.4 * corner_distance}, {0., 0.7 * corner_distance}, {0., corner_distance} + }}; + std::vector curve_coefficients; + flatten_bezier(corner_curve, deviation, curve_coefficients); + + auto translated_point = [min_x, min_y](size_t idx) { + Point p = hilbert_n_to_xy(idx); + return Point(p.x() + min_x, p.y() + min_y); + }; + auto to_vec2d = [](const Point &p) { return Vec2d(double(p.x()), double(p.y())); }; + bool has_last_output = false; + Vec2d last_output; + // Fully smoothed adjacent corners may meet at the same segment midpoint. Suppress such duplicates + // to avoid emitting zero-length extrusion segments. + auto add_point = [&output, &has_last_output, &last_output](const Vec2d &point) { + if (!has_last_output || point.x() != last_output.x() || point.y() != last_output.y()) { + output.add_point(point); + last_output = point; + has_last_output = true; + } + }; + + Vec2d previous = to_vec2d(translated_point(0)); + Vec2d corner = to_vec2d(translated_point(1)); + add_point(previous); + // Replace each non-collinear Hilbert vertex by the canonical curve expressed in the local basis of + // its incoming and outgoing unit vectors. Collinear vertices remain part of the straight polyline. + for (size_t i = 1; i + 1 < point_count; ++i) { + const Vec2d next = to_vec2d(translated_point(i + 1)); + const Vec2d incoming = (corner - previous).normalized(); + const Vec2d outgoing = (next - corner).normalized(); + const double cross = incoming.x() * outgoing.y() - incoming.y() * outgoing.x(); + + if (std::abs(cross) < EPSILON) { + add_point(corner); + } else { + add_point(corner - corner_distance * incoming); + for (const Vec2d &coefficient : curve_coefficients) + add_point(corner + coefficient.x() * incoming + coefficient.y() * outgoing); + } + + previous = corner; + corner = next; + } + add_point(corner); +} + void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */, InfillPolylineOutput &output) { if (output.clips()) @@ -296,6 +437,24 @@ void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coo generate_hilbert_curve(min_x, min_y, max_x, max_y, output); } +void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams ¶ms, InfillPolylineOutput &output) +{ + const double smooth_factor = std::isfinite(params.smooth_factor) ? + std::clamp(params.smooth_factor, 0., 1.) : 0.; + if (smooth_factor == 0.) { + this->generate(min_x, min_y, max_x, max_y, resolution, output); + return; + } + + const double corner_distance = 0.5 * smooth_factor; + if (output.clips()) + generate_smooth_hilbert_curve( + min_x, min_y, max_x, max_y, resolution, corner_distance, static_cast(output)); + else + generate_smooth_hilbert_curve(min_x, min_y, max_x, max_y, resolution, corner_distance, output); +} + template static void generate_octagram_spiral(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, Output &output) { diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index 1371e8506a..b4b25b73ae 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -53,6 +53,11 @@ protected: friend class InfillPolylineClipper; virtual void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) = 0; + virtual void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams & /* params */, InfillPolylineOutput &output) + { + this->generate(min_x, min_y, max_x, max_y, resolution, output); + } }; class FillArchimedeanChords : public FillPlanePath @@ -75,6 +80,8 @@ public: protected: bool centered() const override { return false; } void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) override; + void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams ¶ms, InfillPolylineOutput &output) override; }; class FillOctagramSpiral : public FillPlanePath diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 775c31b563..3bd277d44a 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1037,6 +1037,7 @@ static std::vector s_Preset_print_options{ "fill_multiline", "gyroid_optimized", "sparse_infill_pattern", + "sparse_infill_smooth_factor", "lateral_lattice_angle_1", "lateral_lattice_angle_2", "infill_overhang_angle", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 17dd195df9..f7222b864f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3457,6 +3457,18 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->set_default_value(new ConfigOptionEnum(ipCrossHatch)); + def = this->add("sparse_infill_smooth_factor", coPercent); + def->label = L("Sparse infill smooth factor"); + def->category = L("Strength"); + def->tooltip = L("Controls how strongly sparse infill corners are rounded. 0% keeps the original right-angle path, " + "while 100% produces the largest possible curves between adjacent infill lines. " + "Currently applies only to the Hilbert Curve."); + def->sidetext = "%"; + def->min = 0; + def->max = 100; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionPercent(0)); + def = this->add("top_surface_acceleration", coFloats); def->label = L("Top surface"); def->category = L("Speed"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 67841c6404..1082c43491 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1264,6 +1264,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionString, sparse_infill_rotate_template)) ((ConfigOptionPercent, sparse_infill_density)) ((ConfigOptionEnum, sparse_infill_pattern)) + ((ConfigOptionPercent, sparse_infill_smooth_factor)) ((ConfigOptionFloat, lateral_lattice_angle_1)) ((ConfigOptionFloat, lateral_lattice_angle_2)) ((ConfigOptionFloat, infill_overhang_angle)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 0ef46fac92..9356f937ab 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1409,6 +1409,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_overhang_angle") { steps.emplace_back(posInfill); } else if (opt_key == "sparse_infill_pattern" + || opt_key == "sparse_infill_smooth_factor" || opt_key == "symmetric_infill_y_axis" || opt_key == "infill_shift_step" || opt_key == "sparse_infill_rotate_template" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index c2643b5d0f..53a3575a57 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -707,6 +707,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in bool has_top_shell = has_top_shell_layers && config->option("top_surface_density")->value > 0; bool has_bottom_shell = config->opt_int("bottom_shell_layers") > 0; bool has_solid_infill = has_top_shell_layers || has_bottom_shell; + toggle_line("sparse_infill_smooth_factor", pattern == ipHilbertCurve); toggle_field("top_surface_pattern", has_top_shell); toggle_field("bottom_surface_pattern", has_bottom_shell); toggle_field("top_surface_density", has_top_shell_layers); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index a4a60ac4bd..5254492e5d 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -123,6 +123,7 @@ std::map> SettingsFactory::PART_CATE {"sparse_infill_density", "", 1}, {"fill_multiline", "", 1}, {"sparse_infill_pattern", "", 1}, + {"sparse_infill_smooth_factor", "", 1}, {"lateral_lattice_angle_1", "", 1}, {"lateral_lattice_angle_2", "", 1}, {"infill_overhang_angle", "", 1}, diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ef830b7f35..01458b368a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2816,6 +2816,7 @@ void TabPrint::build() optgroup->append_single_option_line("fill_multiline", "strength_settings_infill#fill-multiline"); optgroup->append_single_option_line("sparse_infill_pattern", "strength_settings_infill#sparse-infill-pattern"); optgroup->append_single_option_line("gyroid_optimized", "strength_settings_patterns#gyroid-optimized"); + optgroup->append_single_option_line("sparse_infill_smooth_factor", "strength_settings_patterns#sparse-infill-smooth-factor"); optgroup->append_single_option_line("infill_direction", "strength_settings_infill#direction"); optgroup->append_single_option_line("sparse_infill_rotate_template", "strength_settings_infill_rotation_template_metalanguage"); optgroup->append_single_option_line("skin_infill_density", "strength_settings_patterns#locked-zag"); diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 7524c27479..dbc6c99f15 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(${_TEST_NAME}_tests test_preset_setting_id.cpp test_preset_diff.cpp test_elephant_foot_compensation.cpp + test_fill_plane_path.cpp test_geometry.cpp test_multimaterial_segmentation.cpp test_placeholder_parser.cpp diff --git a/tests/libslic3r/test_fill_plane_path.cpp b/tests/libslic3r/test_fill_plane_path.cpp new file mode 100644 index 0000000000..bbb75dce58 --- /dev/null +++ b/tests/libslic3r/test_fill_plane_path.cpp @@ -0,0 +1,164 @@ +#include + +#include +#include +#include +#include + +#include "libslic3r/Fill/FillPlanePath.hpp" +#include "libslic3r/PrintConfig.hpp" + +using namespace Slic3r; + +namespace { + +constexpr double output_scale = 1'000'000.; + +class TestableHilbertCurve : public FillHilbertCurve +{ +public: + Points generate_points(double resolution, double smooth_factor = 0., coord_t max_coordinate = 7) + { + InfillPolylineOutput output(output_scale); + FillParams params; + params.smooth_factor = smooth_factor; + FillHilbertCurve::generate(0, 0, max_coordinate, max_coordinate, resolution, params, output); + return std::move(output.result()); + } +}; + +double path_length(const Points &points) +{ + double length = 0.; + for (size_t i = 1; i < points.size(); ++i) + length += (points[i] - points[i - 1]).cast().norm(); + return length; +} + +double discrete_curvature_at(const Points &points, const Point &point) +{ + const auto point_it = std::find(points.begin(), points.end(), point); + REQUIRE(point_it != points.end()); + const size_t point_idx = size_t(std::distance(points.begin(), point_it)); + REQUIRE(point_idx > 0); + REQUIRE(point_idx + 1 < points.size()); + + const Vec2d incoming = (points[point_idx] - points[point_idx - 1]).cast() / output_scale; + const Vec2d outgoing = (points[point_idx + 1] - points[point_idx]).cast() / output_scale; + const Vec2d chord = incoming + outgoing; + const double cross = std::abs(incoming.x() * outgoing.y() - incoming.y() * outgoing.x()); + return 2. * cross / (incoming.norm() * outgoing.norm() * chord.norm()); +} + +} // namespace + +TEST_CASE("Hilbert curve exposes a smoothing factor", "[FillPlanePath]") +{ + const ConfigOptionDef *factor_def = print_config_def.get("sparse_infill_smooth_factor"); + REQUIRE(factor_def != nullptr); + REQUIRE(factor_def->type == coPercent); + REQUIRE_THAT(factor_def->min, Catch::Matchers::WithinAbs(0., 1e-12)); + REQUIRE_THAT(factor_def->max, Catch::Matchers::WithinAbs(100., 1e-12)); + REQUIRE_THAT(factor_def->get_default_value()->value, + Catch::Matchers::WithinAbs(0., 1e-12)); +} + +TEST_CASE("Hilbert curve smoothing rounds right angle turns", "[FillPlanePath]") +{ + const Points sharp = TestableHilbertCurve().generate_points(0.005); + const Points smooth = TestableHilbertCurve().generate_points(0.005, 1.); + + REQUIRE(smooth.front() == sharp.front()); + REQUIRE(smooth.back() == sharp.back()); + REQUIRE(smooth.size() > sharp.size()); + + bool has_turn = false; + for (size_t i = 1; i < smooth.size(); ++i) { + const Vec2d segment = (smooth[i] - smooth[i - 1]).cast(); + REQUIRE(segment.squaredNorm() > 0.); + } + for (size_t i = 1; i + 1 < smooth.size(); ++i) { + const Vec2d incoming = (smooth[i] - smooth[i - 1]).cast(); + const Vec2d outgoing = (smooth[i + 1] - smooth[i]).cast(); + const double cross = incoming.x() * outgoing.y() - incoming.y() * outgoing.x(); + const double cosine = incoming.dot(outgoing) / (incoming.norm() * outgoing.norm()); + has_turn |= std::abs(cross) > 0.; + REQUIRE(cosine > 0.); + } + REQUIRE(has_turn); + + const coord_t upper_bound = coord_t(7 * output_scale); + for (const Point &point : smooth) { + REQUIRE(point.x() >= 0); + REQUIRE(point.y() >= 0); + REQUIRE(point.x() <= upper_bound); + REQUIRE(point.y() <= upper_bound); + } +} + +TEST_CASE("Smoothed Hilbert curve honors path resolution", "[FillPlanePath]") +{ + const Points coarse = TestableHilbertCurve().generate_points(0.1, 1.); + const Points fine = TestableHilbertCurve().generate_points(0.001, 1.); + + REQUIRE(fine.size() > coarse.size()); + REQUIRE(fine.front() == coarse.front()); + REQUIRE(fine.back() == coarse.back()); +} + +TEST_CASE("Smoothed Hilbert corners use a uniform subdivision depth", "[FillPlanePath]") +{ + const Points smooth = TestableHilbertCurve().generate_points(0.0035, 1., 1); + const Point curve_entry(0, coord_t(0.5 * output_scale)); + const Point curve_exit(coord_t(0.5 * output_scale), coord_t(output_scale)); + + const auto entry_it = std::find(smooth.begin(), smooth.end(), curve_entry); + REQUIRE(entry_it != smooth.end()); + const auto exit_it = std::find(entry_it, smooth.end(), curve_exit); + REQUIRE(exit_it != smooth.end()); + + const size_t segment_count = size_t(std::distance(entry_it, exit_it)); + REQUIRE(segment_count > 1); + REQUIRE((segment_count & (segment_count - 1)) == 0); + + double previous_length = (entry_it[1] - entry_it[0]).cast().norm(); + REQUIRE(previous_length > 0.); + double max_length_ratio = 1.; + for (size_t segment = 1; segment < segment_count; ++segment) { + const double current_length = (entry_it[segment + 1] - entry_it[segment]).cast().norm(); + REQUIRE(current_length > 0.); + max_length_ratio = std::max(max_length_ratio, + std::max(current_length / previous_length, previous_length / current_length)); + previous_length = current_length; + } + REQUIRE(max_length_ratio < 1.5); +} + +TEST_CASE("Hilbert smoothing joins straight segments with continuous curvature", "[FillPlanePath]") +{ + const Points coarse = TestableHilbertCurve().generate_points(0.005, 0.5, 1); + const Points fine = TestableHilbertCurve().generate_points(0.0001, 0.5, 1); + const Point first_curve_entry(0, coord_t(0.75 * output_scale)); + + const double coarse_entry_curvature = discrete_curvature_at(coarse, first_curve_entry); + const double fine_entry_curvature = discrete_curvature_at(fine, first_curve_entry); + REQUIRE(coarse_entry_curvature > 0.); + REQUIRE(fine_entry_curvature < 0.25 * coarse_entry_curvature); +} + +TEST_CASE("Hilbert curve smooth factor controls corner curvature", "[FillPlanePath]") +{ + const Points sharp = TestableHilbertCurve().generate_points(0.005); + const Points half_smooth = TestableHilbertCurve().generate_points(0.005, 0.5); + const Points full_smooth = TestableHilbertCurve().generate_points(0.005, 1.); + const Points invalid_factor = TestableHilbertCurve().generate_points( + 0.005, std::numeric_limits::quiet_NaN()); + + REQUIRE(full_smooth.front() == half_smooth.front()); + REQUIRE(full_smooth.back() == half_smooth.back()); + REQUIRE(path_length(full_smooth) < path_length(half_smooth)); + REQUIRE(invalid_factor == sharp); + + for (size_t i = 1; i < full_smooth.size(); ++i) + REQUIRE((full_smooth[i] - full_smooth[i - 1]).squaredNorm() > 0); +} From 13ae3a1c90781b555db06cb3811b9f1705be9d99 Mon Sep 17 00:00:00 2001 From: maddavo <1432875+maddavo@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:54:16 +1000 Subject: [PATCH 07/23] Add outer-only mouse ears and align ear radius controls (#15015) Improve mouse ear brim controls --- src/libslic3r/Brim.cpp | 16 +-- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 7 + src/libslic3r/PrintConfig.hpp | 1 + src/libslic3r/PrintObject.cpp | 1 + src/slic3r/GUI/ConfigManipulation.cpp | 21 ++- src/slic3r/GUI/ConfigManipulation.hpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp | 70 +++++----- src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp | 4 +- src/slic3r/GUI/OptionsGroup.cpp | 2 + src/slic3r/GUI/OptionsGroup.hpp | 9 ++ src/slic3r/GUI/Tab.cpp | 14 +- src/slic3r/GUI/Tab.hpp | 1 + tests/fff_print/test_skirt_brim.cpp | 150 ++++++++++++++++++++++ 14 files changed, 252 insertions(+), 53 deletions(-) diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index b22c9c323e..9cee5a0e4b 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -349,7 +349,7 @@ static ExPolygons make_brim_ears_auto(const ExPolygons& obj_expoly, coord_t size return mouse_ears_ex; } -static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWidth, float brim_offset, Flow &flow, bool is_outer_brim) +static ExPolygons make_brim_ears(const PrintObject* object) { ExPolygons mouse_ears_ex; BrimPoints brim_ear_points = object->model_object()->brim_points; @@ -373,12 +373,7 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi Vec3f world_pos = pt.transform(trsf.get_matrix()); if ( world_pos.z() > 0) continue; Polygon point_round; - float brim_width = floor(scale_(pt.head_front_radius) / flowWidth / 2) * flowWidth * 2; - if (is_outer_brim) { - double flowWidthScale = flowWidth / SCALING_FACTOR; - brim_width = floor(brim_width / flowWidthScale / 2) * flowWidthScale * 2; - } - coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); + const coord_t size_ear = scale_(pt.head_front_radius); for (size_t i = 0; i < POLY_SIDE_COUNT; i++) { double angle = (2.0 * PI * i) / POLY_SIDE_COUNT; point_round.points.emplace_back(size_ear * cos(angle), size_ear * sin(angle)); @@ -452,7 +447,8 @@ static ExPolygons outer_inner_brim_area(const Print& print, bool has_brim_auto = object->config().brim_type == btAutoBrim; const bool use_auto_brim_ears = object->config().brim_type == btEar; const bool use_brim_ears = object->config().brim_type == btPainted; - const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_auto_brim_ears || use_brim_ears; + const bool use_inner_brim_ears = (use_auto_brim_ears || use_brim_ears) && !object->config().brim_ears_outer_only.value; + const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_inner_brim_ears; const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || use_auto_brim_ears || use_brim_ears; coord_t ear_detection_length = scale_(object->config().brim_ears_detection_length.value); coordf_t brim_ears_max_angle = object->config().brim_ears_max_angle.value; @@ -531,7 +527,7 @@ static ExPolygons outer_inner_brim_area(const Print& print, auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION); ExPolygons outerExpoly; if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true); + outerExpoly = make_brim_ears(object); //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); } else if (use_auto_brim_ears) { coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing()); @@ -545,7 +541,7 @@ static ExPolygons outer_inner_brim_area(const Print& print, ExPolygons outerExpoly; auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset); if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false); + outerExpoly = make_brim_ears(object); } else if (use_auto_brim_ears) { coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 3bd277d44a..2821bef0af 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1091,7 +1091,7 @@ static std::vector s_Preset_print_options{ "top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed", "bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed", "outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield", - "brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", + "brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "brim_ears_outer_only", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style", // BBS diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f7222b864f..cc991f91cc 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1937,6 +1937,13 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(1)); + def = this->add("brim_ears_outer_only", coBool); + def->label = L("Brim ears outer only"); + def->category = L("Support"); + def->tooltip = L("Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("compatible_printers", coStrings); def->label = L("Select printers"); def->mode = comAdvanced; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 1082c43491..90aa1adb3d 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1082,6 +1082,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, brim_width)) ((ConfigOptionFloat, brim_ears_detection_length)) ((ConfigOptionFloat, brim_ears_max_angle)) + ((ConfigOptionBool, brim_ears_outer_only)) ((ConfigOptionFloat, skirt_start_angle)) ((ConfigOptionBool, bridge_no_support)) ((ConfigOptionFloat, elefant_foot_compensation)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 9356f937ab..b2a92f11a6 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1175,6 +1175,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "brim_type" || opt_key == "brim_ears_max_angle" || opt_key == "brim_ears_detection_length" + || opt_key == "brim_ears_outer_only" // BBS: brim generation depends on printing speed || opt_key == "outer_wall_speed" || opt_key == "small_perimeter_speed" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 53a3575a57..e46faa803a 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -70,6 +70,12 @@ void ConfigManipulation::toggle_line(const std::string& opt_key, const bool togg cb_toggle_line(opt_key, toggle, opt_index); } +void ConfigManipulation::set_option_label(const std::string& opt_key, const wxString& label, int opt_index) +{ + if (cb_set_option_label) + cb_set_option_label(opt_key, label, opt_index); +} + void ConfigManipulation::check_nozzle_recommended_temperature_range(DynamicPrintConfig *config) { if (is_msg_dlg_already_exist) return; @@ -808,14 +814,19 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in toggle_field("outer_wall_filament_id", have_perimeters || have_brim); toggle_field("inner_wall_filament_id", have_perimeters || have_brim); - bool have_brim_ear = (config->opt_enum("brim_type") == btEar); + const BrimType brim_type = config->opt_enum("brim_type"); + const bool have_auto_brim_ear = brim_type == btEar; + const bool have_painted_brim_ear = brim_type == btPainted; + set_option_label("brim_width", have_auto_brim_ear ? _L("Brim ear radius") : _L("Brim width")); const auto brim_width = config->opt_float("brim_width"); - // disable brim_ears_max_angle and brim_ears_detection_length if brim_width is 0 + // Automatic brim ear settings require a non-zero brim width. toggle_field("brim_ears_max_angle", brim_width > 0.0f); toggle_field("brim_ears_detection_length", brim_width > 0.0f); - // hide brim_ears_max_angle and brim_ears_detection_length if brim_ear is not selected - toggle_line("brim_ears_max_angle", have_brim_ear); - toggle_line("brim_ears_detection_length", have_brim_ear); + // Painted ears carry their own radius and do not depend on brim_width. + toggle_field("brim_ears_outer_only", have_painted_brim_ear || brim_width > 0.0f); + toggle_line("brim_ears_max_angle", have_auto_brim_ear); + toggle_line("brim_ears_detection_length", have_auto_brim_ear); + toggle_line("brim_ears_outer_only", have_auto_brim_ear || have_painted_brim_ear); // Hide Elephant foot compensation layers if elefant_foot_compensation is not enabled toggle_line("elefant_foot_compensation_layers", config->opt_float("elefant_foot_compensation") > 0 || config->option("elefant_foot_layers_density")->get_abs_value(1.0f) < 1.0f); diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index 0ad1fb0b7c..d191ef2c4f 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -29,6 +29,7 @@ class ConfigManipulation std::function load_config = nullptr; std::function cb_toggle_field = nullptr; std::function cb_toggle_line = nullptr; + std::function cb_set_option_label = nullptr; // callback to propagation of changed value, if needed std::function cb_value_change = nullptr; //BBS: change local config to const DynamicPrintConfig @@ -45,10 +46,12 @@ public: std::function cb_value_change, //BBS: change local config to DynamicPrintConfig const DynamicPrintConfig* local_config = nullptr, - wxWindow* msg_dlg_parent = nullptr) : + wxWindow* msg_dlg_parent = nullptr, + std::function cb_set_option_label = nullptr) : load_config(load_config), cb_toggle_field(cb_toggle_field), cb_toggle_line(cb_toggle_line), + cb_set_option_label(cb_set_option_label), cb_value_change(cb_value_change), m_msg_dlg_parent(msg_dlg_parent), local_config(local_config) {} @@ -58,6 +61,7 @@ public: load_config = nullptr; cb_toggle_field = nullptr; cb_toggle_line = nullptr; + cb_set_option_label = nullptr; cb_value_change = nullptr; } @@ -67,6 +71,7 @@ public: t_config_option_keys const &applying_keys() const; void toggle_field(const std::string& field_key, const bool toggle, int opt_index = -1); void toggle_line(const std::string& field_key, const bool toggle, int opt_index = -1); + void set_option_label(const std::string& field_key, const wxString& label, int opt_index = -1); // FFF print void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false, const bool is_plate_config = false); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp index 45aaf37a86..709e7b5b21 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp @@ -15,6 +15,8 @@ static const ColorRGBA DEF_COLOR = {0.7f, 0.7f, 0.7f, 1.f}; static const ColorRGBA SELECTED_COLOR = {0.0f, 0.5f, 0.5f, 1.0f}; static const ColorRGBA ERR_COLOR = {1.0f, 0.3f, 0.3f, 0.5f}; static const ColorRGBA HOVER_COLOR = {0.7f, 0.7f, 0.7f, 0.5f}; +static constexpr float BRIM_EAR_RADIUS_MIN = 0.1f; +static constexpr float BRIM_EAR_RADIUS_MAX = 100.f; static ModelVolume *get_model_volume(const Selection &selection, Model &model) { @@ -41,14 +43,14 @@ GLGizmoBrimEars::GLGizmoBrimEars(GLCanvas3D &parent, const std::string &icon_fil bool GLGizmoBrimEars::on_init() { - m_new_point_head_diameter = get_brim_default_radius(); + m_new_point_head_radius = get_brim_default_radius(); m_shortcut_key = WXK_CONTROL_E; const wxString ctrl = GUI::shortkey_ctrl_prefix(); const wxString alt = GUI::shortkey_alt_prefix(); - m_desc["head_diameter"] = _L("Head diameter"); + m_desc["brim_ear_radius"] = _L("Brim ear radius"); m_desc["max_angle"] = _L("Max angle"); m_desc["detection_radius"] = _L("Detection radius"); m_desc["remove"] = _L("Remove"); @@ -62,7 +64,7 @@ bool GLGizmoBrimEars::on_init() m_shortcuts = { {_L("Left mouse button"), _L("Add or Select")}, {_L("Right mouse button"), _L("Remove")}, - {ctrl + _L("Mouse wheel"), m_desc["head_diameter"]}, + {ctrl + _L("Mouse wheel"), m_desc["brim_ear_radius"]}, {alt + _L("Mouse wheel"), m_desc["section_view"]}, }; @@ -358,7 +360,7 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p Transform3d inverse_trsf = volume->get_instance_transformation().get_matrix_no_offset().inverse(); std::pair pos_and_normal; if (unproject_on_mesh2(mouse_position, pos_and_normal)) { - render_hover_point = CacheEntry(BrimPoint(pos_and_normal.first, m_new_point_head_diameter / 2.f), false, (inverse_trsf * m_world_normal).cast(), true); + render_hover_point = CacheEntry(BrimPoint(pos_and_normal.first, m_new_point_head_radius), false, (inverse_trsf * m_world_normal).cast(), true); } else { render_hover_point.reset(); } @@ -397,7 +399,7 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p Vec3d object_pos = trsf.inverse() * world_pos; // brim ear always face up Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Add brim ear"); - add_point_to_cache(object_pos.cast(), m_new_point_head_diameter / 2.f, false, (inverse_trsf * m_world_normal).cast()); + add_point_to_cache(object_pos.cast(), m_new_point_head_radius, false, (inverse_trsf * m_world_normal).cast()); m_parent.set_as_dirty(); m_wait_for_up_event = true; find_single(); @@ -490,9 +492,9 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p // mouse wheel up if (action == SLAGizmoEventType::MouseWheelUp) { if (control_down) { - float initial_value = m_new_point_head_diameter; + float initial_value = m_new_point_head_radius; begin_radius_change(initial_value); - m_new_point_head_diameter = std::min(20., initial_value + 0.1); + m_new_point_head_radius = std::min(BRIM_EAR_RADIUS_MAX, initial_value + 0.1f); update_cache_radius(); return true; } @@ -502,9 +504,9 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p if (action == SLAGizmoEventType::MouseWheelDown) { if (control_down) { - float initial_value = m_new_point_head_diameter; + float initial_value = m_new_point_head_radius; begin_radius_change(initial_value); - m_new_point_head_diameter = std::max(5., initial_value - 0.1); + m_new_point_head_radius = std::max(BRIM_EAR_RADIUS_MIN, initial_value - 0.1f); update_cache_radius(); return true; } @@ -597,18 +599,18 @@ std::vector GLGizmoBrimEars::get_config_options(const std: void GLGizmoBrimEars::begin_radius_change(float initial_value) { - if (m_old_point_head_diameter == 0.f) - m_old_point_head_diameter = initial_value; + if (m_old_point_head_radius == 0.f) + m_old_point_head_radius = initial_value; } void GLGizmoBrimEars::update_cache_radius() { if (render_hover_point) - render_hover_point->brim_point.head_front_radius = m_new_point_head_diameter / 2.f; + render_hover_point->brim_point.head_front_radius = m_new_point_head_radius; for (auto &cache_entry : m_editing_cache) if (cache_entry.selected) { - cache_entry.brim_point.head_front_radius = m_new_point_head_diameter / 2.f; + cache_entry.brim_point.head_front_radius = m_new_point_head_radius; find_single(); update_model_object(); } @@ -617,18 +619,18 @@ void GLGizmoBrimEars::update_cache_radius() void GLGizmoBrimEars::apply_radius_change() { - if (m_old_point_head_diameter == 0.f) return; + if (m_old_point_head_radius == 0.f) return; // momentarily restore the old value to take snapshot for (auto& cache_entry : m_editing_cache) if (cache_entry.selected) - cache_entry.brim_point.head_front_radius = m_old_point_head_diameter / 2.f; - float backup = m_new_point_head_diameter; - m_new_point_head_diameter = m_old_point_head_diameter; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Change point head diameter"); - m_new_point_head_diameter = backup; + cache_entry.brim_point.head_front_radius = m_old_point_head_radius; + float backup = m_new_point_head_radius; + m_new_point_head_radius = m_old_point_head_radius; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Change brim ear radius"); + m_new_point_head_radius = backup; update_cache_radius(); - m_old_point_head_diameter = 0.f; + m_old_point_head_radius = 0.f; } void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limit) @@ -653,7 +655,7 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); float space_size = m_imgui->get_style_scaling() * 8; - std::vector text_list = {m_desc["head_diameter"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"], + std::vector text_list = {m_desc["brim_ear_radius"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"], m_desc["create"], m_desc["remove"]}; float widest_text = m_imgui->find_widest_text(text_list); float caption_size = widest_text + space_size + ImGui::GetStyle().WindowPadding.x; @@ -680,11 +682,11 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi // - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene // - take correct undo/redo snapshot after the user is done with moving the slider ImGui::AlignTextToFramePadding(); - float initial_value = m_new_point_head_diameter; - m_imgui->text(m_desc["head_diameter"]); + float initial_value = m_new_point_head_radius; + m_imgui->text(m_desc["brim_ear_radius"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(slider_width); - m_imgui->bbl_slider_float_style("##head_diameter", &m_new_point_head_diameter, 5, 20, "%.1f", 1.0f, true); + m_imgui->bbl_slider_float_style("##brim_ear_radius", &m_new_point_head_radius, BRIM_EAR_RADIUS_MIN, BRIM_EAR_RADIUS_MAX, "%.1f", 1.0f, true); if (m_imgui->get_last_slider_status().clicked) { begin_radius_change(initial_value); } @@ -695,7 +697,7 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi } ImGui::SameLine(drag_left_width); ImGui::PushItemWidth(1.5 * slider_icon_width); - ImGui::BBLDragFloat("##head_diameter_input", &m_new_point_head_diameter, 0.05f, 0.0f, 0.0f, "%.1f"); + ImGui::BBLDragFloat("##brim_ear_radius_input", &m_new_point_head_radius, 0.05f, BRIM_EAR_RADIUS_MIN, BRIM_EAR_RADIUS_MAX, "%.1f"); ImGui::Separator(); @@ -910,9 +912,9 @@ void GLGizmoBrimEars::on_stop_dragging() m_point_before_drag = CacheEntry(); } -void GLGizmoBrimEars::on_load(cereal::BinaryInputArchive &ar) { ar(m_new_point_head_diameter, m_editing_cache, m_selection_empty); } +void GLGizmoBrimEars::on_load(cereal::BinaryInputArchive &ar) { ar(m_new_point_head_radius, m_editing_cache, m_selection_empty); } -void GLGizmoBrimEars::on_save(cereal::BinaryOutputArchive &ar) const { ar(m_new_point_head_diameter, m_editing_cache, m_selection_empty); } +void GLGizmoBrimEars::on_save(cereal::BinaryOutputArchive &ar) const { ar(m_new_point_head_radius, m_editing_cache, m_selection_empty); } void GLGizmoBrimEars::select_point(int i) { @@ -920,11 +922,11 @@ void GLGizmoBrimEars::select_point(int i) for (auto &point_and_selection : m_editing_cache) point_and_selection.selected = (i == AllPoints); m_selection_empty = (i == NoPoints); - if (i == AllPoints) m_new_point_head_diameter = m_editing_cache[0].brim_point.head_front_radius * 2.f; + if (i == AllPoints) m_new_point_head_radius = m_editing_cache[0].brim_point.head_front_radius; } else { m_editing_cache[i].selected = true; m_selection_empty = false; - m_new_point_head_diameter = m_editing_cache[i].brim_point.head_front_radius * 2.f; + m_new_point_head_radius = m_editing_cache[i].brim_point.head_front_radius; } } @@ -1011,8 +1013,7 @@ void GLGizmoBrimEars::auto_generate() auto add_point = [this, &trsf, &normal](const Point &p) { Vec3d world_pos = {float(p.x() * SCALING_FACTOR), float(p.y() * SCALING_FACTOR), -0.0001}; Vec3d object_pos = trsf.inverse() * world_pos; - // m_editing_cache.emplace_back(BrimPoint(object_pos.cast(), m_new_point_head_diameter / 2), false, normal); - add_point_to_cache(object_pos.cast(), m_new_point_head_diameter / 2, false, normal); + add_point_to_cache(object_pos.cast(), m_new_point_head_radius, false, normal); }; for (const ExPolygon &ex_poly : m_first_layer) { Polygon out_poly = ex_poly.contour; @@ -1158,8 +1159,11 @@ void GLGizmoBrimEars::reset_all_pick() { std::mapprinters.get_edited_preset().config.option("nozzle_diameter")->get_at(0); - const DynamicPrintConfig &pring_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - return pring_cfg.get_abs_value("initial_layer_line_width", nozzle_diameter) * 16.0f; + const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; + return std::clamp( + float(print_cfg.get_abs_value("initial_layer_line_width", nozzle_diameter) * 8.0), + BRIM_EAR_RADIUS_MIN, + BRIM_EAR_RADIUS_MAX); } ExPolygon GLGizmoBrimEars::make_polygon(BrimPoint point, const Geometry::Transformation &trsf) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp index 8b1ff2ca62..4e531e6acc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp @@ -98,12 +98,12 @@ private: void render_points(const Selection& selection); - float m_new_point_head_diameter; // Size of a new point. + float m_new_point_head_radius; // Radius of a new point. float m_max_angle = 125.f; float m_detection_radius = 1.f; double m_detection_radius_max = .0f; CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited - float m_old_point_head_diameter = 0.; // the same + float m_old_point_head_radius = 0.; // the same mutable std::vector m_editing_cache; // a support point and whether it is currently selectedchanges or undo/redo std::map m_single_brim; ObjectID m_old_mo_id; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 0f6cdba602..9fb4483883 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -386,6 +386,7 @@ void OptionsGroup::activate_line(Line& line) } if (label != nullptr && line.label_tooltip != "") label->SetToolTip(line.label_tooltip); + line.label_widget = label; } } @@ -574,6 +575,7 @@ void OptionsGroup::clear(bool destroy_custom_ctrl) for (Line& line : m_lines) { if (line.near_label_widget_win) line.near_label_widget_win = nullptr; + line.label_widget = nullptr; if (line.widget_sizer) { line.widget_sizer->Clear(true); diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 5e1f55dfd8..c808545145 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -62,6 +62,7 @@ public: widget_t widget {nullptr}; std::function near_label_widget{ nullptr }; wxWindow* near_label_widget_win {nullptr}; + wxStaticText* label_widget {nullptr}; wxSizer* widget_sizer {nullptr}; wxSizer* extra_widget_sizer {nullptr}; //BBS: export the extra colume widget @@ -81,6 +82,14 @@ public: label(_(label)), label_tooltip(_(tooltip)) {} Line() : m_is_separator(true) {} + void set_label(const wxString& new_label) { + label = new_label; + if (label_widget != nullptr) { + label_widget->SetLabel(label + (label.IsEmpty() ? "" : ": ")); + label_widget->Refresh(); + } + } + bool is_separator() const { return m_is_separator; } bool has_only_option(const std::string& opt_key) const { return m_options.size() == 1 && m_options[0].opt_id == opt_key; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 01458b368a..c8fa524ca5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1738,6 +1738,13 @@ void Tab::toggle_line(const std::string &opt_key, bool toggle, int opt_index) if (line) line->toggle_visible = toggle; }; +void Tab::set_option_label(const std::string &opt_key, const wxString &label, int opt_index) +{ + if (!m_active_page) return; + Line *line = m_active_page->get_line(opt_key, opt_index); + if (line) line->set_label(label); +} + // To be called by custom widgets, load a value into a config, // update the preset selection boxes (the dirty flags) // If value is saved before calling this function, put saved_value = true, @@ -3070,6 +3077,7 @@ void TabPrint::build() optgroup->append_single_option_line("combine_brims", "others_settings_brim#combine-brims"); optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle"); optgroup->append_single_option_line("brim_ears_detection_length", "others_settings_brim#ear-detection-radius"); + optgroup->append_single_option_line("brim_ears_outer_only"); optgroup = page->new_optgroup(L("Special mode"), L"param_special"); optgroup->append_single_option_line("slicing_mode", "others_settings_special_mode#slicing-mode"); @@ -8935,11 +8943,15 @@ ConfigManipulation Tab::get_config_manipulation() return toggle_line(opt_key, toggle, opt_index >= 0 ? opt_index + 256 : opt_index); }; + auto cb_set_option_label = [this](const t_config_option_key &opt_key, const wxString &label, int opt_index) { + return set_option_label(opt_key, label, opt_index >= 0 ? opt_index + 256 : opt_index); + }; + auto cb_value_change = [this](const std::string& opt_key, const boost::any& value) { return on_value_change(opt_key, value); }; - return ConfigManipulation(load_config, cb_toggle_field, cb_toggle_line, cb_value_change, nullptr, this); + return ConfigManipulation(load_config, cb_toggle_field, cb_toggle_line, cb_value_change, nullptr, this, cb_set_option_label); } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 9be9bc17f8..7187aff467 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -402,6 +402,7 @@ public: Field* get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1); void toggle_option(const std::string &opt_key, bool toggle, int opt_index = -1); void toggle_line(const std::string &opt_key, bool toggle, int opt_index = -1); // BBS: hide some line + void set_option_label(const std::string &opt_key, const wxString &label, int opt_index = -1); wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString); bool current_preset_is_dirty() const; bool saved_preset_is_dirty() const; diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 3f63d3de5f..17a79a7828 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -4,6 +4,7 @@ #include "libslic3r/Config.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/Layer.hpp" #include @@ -32,6 +33,30 @@ static size_t brim_loop_count(Print &print) return n; } +static bool brim_enters_first_layer_hole(Print &print) +{ + const PrintObject *object = print.get_object(0); + Polygons holes; + for (const ExPolygon &slice : object->layers().front()->lslices) + holes.insert(holes.end(), slice.holes.begin(), slice.holes.end()); + + const Vec3d plate_origin = print.get_plate_origin(); + Point shift = object->instances().front().shift_without_plate_offset(); + shift += Point(scaled(plate_origin.x()), scaled(plate_origin.y())); + for (Polygon &hole : holes) + hole.translate(shift); + + for (const auto &kv : print.get_brimMap()) { + Polylines brim_paths; + kv.second.collect_polylines(brim_paths); + for (const Polyline &path : brim_paths) + for (const Point &point : path.points) + if (contains(holes, point, false)) + return true; + } + return false; +} + // The span is skirt_height layers, or every layer when a draft shield is on (forced even at // height 0); per-object skirts are rejected in By object printing (no room between objects). TEST_CASE("Skirt is emitted once per layer it spans", "[SkirtBrim]") @@ -225,6 +250,131 @@ TEST_CASE("Brim ears appear only at corners within the max angle", "[SkirtBrim]" } } +TEST_CASE("Outer-only brim ears stay out of model holes", "[SkirtBrim]") +{ + const bool outer_only = GENERATE(false, true); + DYNAMIC_SECTION("brim_ears_outer_only=" << outer_only) { + Print print; + init_and_process_print({ TestMesh::cube_with_concave_hole }, print, { + { "skirt_loops", 0 }, + { "brim_type", "brim_ears" }, + { "brim_width", 2 }, + { "brim_ears_max_angle", 125 }, + { "brim_ears_detection_length", 0 }, + { "brim_ears_outer_only", outer_only }, + { "initial_layer_line_width", 0.5 }, + }); + + REQUIRE(brim_loop_count(print) > 0); + CHECK(brim_enters_first_layer_hole(print) != outer_only); + } +} + +TEST_CASE("Painted brim ear radius controls sliced size", "[SkirtBrim]") +{ + constexpr double ear_radius = 10.0; + + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "skirt_loops", 0 }, + { "brim_type", "painted" }, + { "brim_width", 15 }, + { "brim_object_gap", 0.1 }, + { "brim_ears_outer_only", true }, + { "initial_layer_line_width", 0.5 }, + }); + + Print print; + Model model; + init_print({ cube(20) }, print, model, config); + print.process(); + + const PrintObject *object = print.get_object(0); + REQUIRE(!object->layers().front()->lslices.empty()); + const Point ear_center = object->layers().front()->lslices.front().contour.points.front(); + + Transform3d model_transform = model.objects.front()->instances.front()->get_transformation().get_matrix_no_offset(); + const Point ¢er_offset = object->center_offset(); + model_transform = model_transform.pretranslate( + Vec3d(-unscale(center_offset.x()), -unscale(center_offset.y()), 0)); + Vec3d model_pos = model_transform.inverse() * + Vec3d(unscale(ear_center.x()), unscale(ear_center.y()), 0); + model_pos.z() = model.objects.front()->raw_mesh_bounding_box().min.z() - 0.0001; + model.objects.front()->brim_points = { + BrimPoint(model_pos.cast(), float(ear_radius)), + }; + + print.apply(model, config); + print.process(); + + const Vec3d plate_origin = print.get_plate_origin(); + Point path_center = ear_center + object->instances().front().shift_without_plate_offset(); + path_center += Point(scaled(plate_origin.x()), scaled(plate_origin.y())); + + double max_path_radius = 0.0; + for (const auto &kv : print.get_brimMap()) { + Polylines brim_paths; + kv.second.collect_polylines(brim_paths); + for (const Polyline &path : brim_paths) + for (const Point &point : path.points) + max_path_radius = std::max(max_path_radius, unscale((point - path_center).cast().norm())); + } + + REQUIRE(max_path_radius > 0.0); + INFO("Outermost painted-ear path radius: " << max_path_radius << " mm"); + CHECK(max_path_radius > ear_radius - 0.5); + CHECK(max_path_radius < ear_radius); +} + +TEST_CASE("Outer-only painted brim ears stay out of model holes", "[SkirtBrim]") +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "skirt_loops", 0 }, + { "brim_type", "painted" }, + { "brim_ears_outer_only", true }, + { "initial_layer_line_width", 0.5 }, + }); + + Print print; + Model model; + init_print({ TestMesh::cube_with_concave_hole }, print, model, config); + + // Slice once to obtain exact outer and inner contour points in print + // coordinates, then express them in the model coordinates painted ears store. + print.process(); + const PrintObject *object = print.get_object(0); + REQUIRE(!object->layers().front()->lslices.empty()); + REQUIRE(!object->layers().front()->lslices.front().holes.empty()); + + Transform3d model_transform = model.objects.front()->instances.front()->get_transformation().get_matrix_no_offset(); + const Point ¢er_offset = object->center_offset(); + model_transform = model_transform.pretranslate( + Vec3d(-unscale(center_offset.x()), -unscale(center_offset.y()), 0)); + const double bottom_z = model.objects.front()->raw_mesh_bounding_box().min.z() - 0.0001; + auto painted_point = [&model_transform, bottom_z](const Point &point) { + Vec3d model_pos = model_transform.inverse() * + Vec3d(unscale(point.x()), unscale(point.y()), 0); + model_pos.z() = bottom_z; + return BrimPoint(model_pos.cast(), 3.f); + }; + + const ExPolygon &first_slice = object->layers().front()->lslices.front(); + Polygon inner_contour = first_slice.holes.front(); + inner_contour.reverse(); + const Points inner_ear_points = inner_contour.concave_points(55. * PI / 180.); + REQUIRE(!inner_ear_points.empty()); + model.objects.front()->brim_points = { + painted_point(first_slice.contour.points.front()), + painted_point(inner_ear_points.front()), + }; + print.apply(model, config); + print.process(); + + REQUIRE(brim_loop_count(print) > 0); + CHECK_FALSE(brim_enters_first_layer_hole(print)); +} + SCENARIO("Skirt has the configured number of loops", "[SkirtBrim]") { GIVEN("20mm cube and default config") { WHEN("skirt_loops is set to 2") { From 6f3ca7d1b919b007e8071bb52b68a8a45403a77e Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 2 Aug 2026 06:01:19 +0300 Subject: [PATCH 08/23] Fix preview speeds and time estimates after firmware retract commands (#15066) --- src/libslic3r/GCode/GCodeProcessor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index d66398354c..cebfe486cb 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -5926,8 +5926,11 @@ void GCodeProcessor::process_G10(const GCodeReader::GCodeLine& line) GCodeReader::GCodeLine g10; g10.set(Axis::E, -this->m_parser.config().retraction_length.get_at(m_extruder_id)); g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(m_extruder_id) * 60); + //Orca: Firmware retract emulation must not change the modal G1 feedrate. + const float feedrate = m_feedrate; --m_g1_line_id; process_G1(g10); + m_feedrate = feedrate; } void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line) @@ -5936,8 +5939,11 @@ void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line) GCodeReader::GCodeLine g11; g11.set(Axis::E, this->m_parser.config().retraction_length.get_at(m_extruder_id) + this->m_parser.config().retract_restart_extra.get_at(m_extruder_id)); g11.set(Axis::F, this->m_parser.config().deretraction_speed.get_at(m_extruder_id) * 60); + // Orca: Firmware unretract emulation must not change the modal G1 feedrate. + const float feedrate = m_feedrate; --m_g1_line_id; process_G1(g11); + m_feedrate = feedrate; } void GCodeProcessor::process_G20(const GCodeReader::GCodeLine& line) From f9fa1c117fd444fadd774ec8957b38e3ed73008b Mon Sep 17 00:00:00 2001 From: "Dipl.-Ing. Raoul Rubien, BSc" Date: Sun, 2 Aug 2026 12:20:35 +0200 Subject: [PATCH 09/23] Define WXINSPECTOR_DISABLE globally to prevent include-order-dependent class layout (#15063) fix: define WXINSPECTOR_DISABLE globally to prevent include-order-dependent class layouts --- CMakeLists.txt | 4 ++++ src/libslic3r/Technologies.hpp | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9417fc906..fc688b35df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,8 +80,12 @@ endif() if (DEFINED BBL_RELEASE_TO_PUBLIC) add_compile_definitions("BBL_RELEASE_TO_PUBLIC=${BBL_RELEASE_TO_PUBLIC}") + if (BBL_RELEASE_TO_PUBLIC) + add_compile_definitions(WXINSPECTOR_DISABLE) + endif () else () add_compile_definitions("BBL_RELEASE_TO_PUBLIC=$") + add_compile_definitions("$<$:WXINSPECTOR_DISABLE>") endif () find_package(Git) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 2dee4bc780..06ebbbf41d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -51,9 +51,4 @@ // Enable extension of tool position imgui dialog to show actual speed profile #define ENABLE_ACTUAL_SPEED_DEBUG 1 -// Disable layout inspector for public release -#if BBL_RELEASE_TO_PUBLIC -#define WXINSPECTOR_DISABLE -#endif - #endif // _prusaslicer_technologies_h_ From 1b718353374c980618a7c855586fbfa6f58a7c17 Mon Sep 17 00:00:00 2001 From: Misterff1 Date: Sun, 2 Aug 2026 12:58:49 +0200 Subject: [PATCH 10/23] Fixed some desktop environments showing title bar on splash screen when running on Wayland (#15019) * Remove titlebar from splash screen on Wayland * Broadly check for window decorations and added explanatory description * Fixed hiding title bar on Wayland for all desktop environments * Update format --------- Co-authored-by: noisyfox --- src/slic3r/GUI/GUI_App.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 07e99348bb..4c4bdfd62c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -307,6 +307,20 @@ public: #endif // !__APPLE__ ) { + // Some desktop environments ignore splash screen typed window properties + // when running the app through Wayland,resulting in the titlebar being shown + // on the splash screen. The code below creates a client-side window decoration + // when running on Wayland and then removes that decoration. This ensures every + // environment correctly targets and removes the titlebar for this screen. + #if defined(__WXGTK__) + if (Slic3r::GUI::is_running_on_wayland()) { + GtkWidget *empty = gtk_fixed_new(); + gtk_widget_set_size_request(empty, 0, 0); + gtk_window_set_titlebar(GTK_WINDOW(GetHandle()), empty); + gtk_window_set_decorated(GTK_WINDOW(GetHandle()), false); + } + #endif + this->SetPosition(pos); this->CenterOnScreen(); From e72a3a65b29fbfb53c0d2eee97b4d618fb7d8a16 Mon Sep 17 00:00:00 2001 From: yw4z Date: Sun, 2 Aug 2026 13:59:53 +0300 Subject: [PATCH 11/23] QOL Continue to capture mouse position while dragging ImGui controls and mouse position goes to outside of window (#14999) * Update GLCanvas3D.cpp * support navigation cube * capture events for transform widgets * camera rotation and pan * selection frame * object drag * fix navigation cube stealing drag events * fix lag on navigation cuve * variable layer height * fix plates toolbar scrollbar * Update GLCanvas3D.cpp * Fix issue that mouse button state is wrong in certain macOS mouse events --------- Co-authored-by: Noisyfox --- src/slic3r/GUI/GLCanvas3D.cpp | 98 +++++++++++++++++++++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 2 +- 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f39761f0ec..a24c095ad6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1842,6 +1842,10 @@ void GLCanvas3D::enable_separator_toolbar(bool enable) m_separator_toolbar.set_enabled(enable); } +bool GLCanvas3D::has_mouse_capture() const { + return m_canvas != nullptr && m_canvas->HasCapture(); +} + void GLCanvas3D::zoom_to_bed() { BoundingBoxf3 box = m_bed.build_volume().bounding_volume(); @@ -2182,7 +2186,7 @@ void GLCanvas3D::render(bool only_init) // Negative coordinate means out of the window, likely because the window was deactivated. // In that case the tooltip should be hidden. - if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.) { + if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0. || has_mouse_capture()) { // ORCA continue to capture mouse pos mid drag if (tooltip.empty()) tooltip = m_layers_editing.get_tooltip(*this); @@ -4170,6 +4174,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // BBS: single snapshot Plater::SingleSnapshot single(wxGetApp().plater()); +#ifdef __WXMAC__ + // On macOS, the mouse key state is only present for mouse btn related events such as wxEVT_LEFT_DOWN. + // For other events, all buttons are reported as non-pressed, such as window leaving event. This causes + // imgui stopped responding if cursor moved out of window, such as + // https://github.com/OrcaSlicer/OrcaSlicer/pull/14999#issuecomment-5151344759 + // We solve this by correcting the state of the event from the actual mouse state querying with `wxGetMouseState()` + // so it works like on other platforms. + { + const auto state = wxGetMouseState(); + evt.SetLeftDown(state.LeftIsDown()); + evt.SetMiddleDown(state.MiddleIsDown()); + evt.SetRightDown(state.RightIsDown()); + evt.SetAux1Down(state.Aux1IsDown()); + evt.SetAux2Down(state.Aux2IsDown()); + } +#endif + #if ENABLE_RETINA_GL const float scale = m_retina_helper->get_scale_factor(); evt.SetX(evt.GetX() * scale); @@ -4183,11 +4204,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // ignore left up events coming from imgui windows and not processed by them m_mouse.ignore_left_up = true; m_tooltip.set_in_imgui(false); - if (imgui->update_mouse_data(evt)) { + + // while a non-ImGui drag is already in progress (gizmo grabber, object move, rectangle selection, layer editing), + // don't let ImGui/ImGuizmo claim the event just because the cursor is hovering something like the navigator cube + // that incorrectly suppresses the active drag's tooltip and can interrupt its processing. The active drag always takes priority. + const bool other_drag_active = m_gizmos.is_dragging() || m_mouse.dragging || m_rectangle_selection.is_dragging() || m_layers_editing.state == LayersEditing::Editing; + + if (imgui->update_mouse_data(evt) && !other_drag_active) { if ((evt.LeftDown() || (evt.Moving() && (evt.AltDown() || evt.ShiftDown()))) && m_canvas != nullptr) m_canvas->SetFocus(); m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast(); m_tooltip.set_in_imgui(true); + + // ORCA keep tracking mouse position while drag active and cursor not in window bounds + const bool imgui_dragging_active = (GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0) || m_navigator_dragging; + if (!has_mouse_capture() && imgui_dragging_active) + m_canvas->CaptureMouse(); + + // release capture as soon as the button goes up + if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) + mouse_up_cleanup(); + render(); #ifdef SLIC3R_DEBUG_MOUSE_EVENTS printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str()); @@ -4284,6 +4321,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_main_toolbar.on_mouse(evt2, *this); } + // ORCA keep tracking mouse position while drag active and cursor not in window bounds + if (!has_mouse_capture() && evt.LeftIsDown() && m_gizmos.is_dragging()) + m_canvas->CaptureMouse(); + if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) mouse_up_cleanup(); @@ -4389,6 +4430,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // Start editing the layer height. m_layers_editing.state = LayersEditing::Editing; _perform_layer_editing_action(&evt); + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); } else { @@ -4402,6 +4446,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) && m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation && m_gizmos.get_current_type() != GLGizmosManager::FuzzySkin) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + m_dirty = true; } } @@ -4469,6 +4517,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.start_position_3D = m_mouse.scene_position; m_sequential_print_clearance_first_displacement = true; m_moving = true; + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); } } } @@ -4477,6 +4528,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.Dragging() && evt.LeftIsDown() && m_mouse.drag.move_volume_idx != -1 && m_layers_editing.state == LayersEditing::Unknown) { if (m_canvas_type != ECanvasType::CanvasAssembleView) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + if (!m_mouse.drag.move_requires_threshold) { m_mouse.dragging = true; Vec3d cur_pos = m_mouse.drag.start_position_3D; @@ -4528,6 +4583,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) { //BBS not in assemble view if (m_canvas_type != ECanvasType::CanvasAssembleView) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + m_rectangle_selection.dragging(pos.cast()); m_dirty = true; } @@ -4537,12 +4596,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) { if (m_layers_editing.state == LayersEditing::Editing) { + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + _perform_layer_editing_action(&evt); m_mouse.position = pos.cast(); } } // do not process the dragging if the left mouse was set down in another canvas else if (is_camera_rotate(evt, button_mappings)) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + // Orca: Sphere rotation for painting view // if dragging over blank area with left button or other button mapped to rotate, then rotate bool middle_or_right_button_used_as_rotate = (evt.MiddleIsDown() && button_mappings[MouseButton::Middle] == MouseAction::Rotation) || @@ -4622,6 +4688,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); } else if (is_camera_pan(evt, button_mappings)) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + // if dragging with right button or if button functions swapped and dragging with left button over blank area then pan if (m_mouse.is_start_position_2D_defined()) { // get point in model space at Z = 0 @@ -6033,9 +6103,18 @@ void GLCanvas3D::_render_3d_navigator() { if (!wxGetApp().show_3d_navigator()) { m_canvas_toolbar_pos[0] = 0; + m_navigator_dragging = false; return; } + // Fix stealing capture event from other drag events + const bool other_drag_active = !m_navigator_dragging && (m_moving || m_rectangle_selection.is_dragging() || m_gizmos.is_dragging() || m_layers_editing.state == LayersEditing::Editing); + + ImGuiIO& io = ImGui::GetIO(); + const bool saved_mouse_down0 = io.MouseDown[0]; + if (other_drag_active) + io.MouseDown[0] = false; + ImGuizmo::BeginFrame(); auto& style = ImGuizmo::GetStyle(); @@ -6060,7 +6139,6 @@ void GLCanvas3D::_render_3d_navigator() sc *= (float) dpi / (float) DPI_DEFAULT; #endif // WIN32 - const ImGuiIO& io = ImGui::GetIO(); const float viewManipulateLeft = 0; const float viewManipulateTop = io.DisplaySize.y; const float camDistance = 8.f; @@ -6084,6 +6162,10 @@ void GLCanvas3D::_render_3d_navigator() camDistance, ImVec2(viewManipulateLeft, viewManipulateTop - size), ImVec2(size, size), 0x00101010); + // Restore the real mouse-down state + if (other_drag_active) + io.MouseDown[0] = saved_mouse_down0; + if (result.changed) { for (unsigned int c = 0; c < 4; ++c) { for (unsigned int r = 0; r < 4; ++r) { @@ -6115,6 +6197,8 @@ void GLCanvas3D::_render_3d_navigator() request_extra_frame(); } + + m_navigator_dragging = result.dragging; } #define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0 @@ -9226,8 +9310,12 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() //ORCA ImGui::IsWindowHovered() returns false when left_down events on buttons that causes scrollbar disappears for a short time auto win_pos = ImGui::GetWindowPos(); - bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll); // use non clipped rectangle to reserve clickable area for scrollbar track - m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered; + bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll); + + // Also show scrollbar visible and continue to capture mouse position + const bool is_scrollbar_active_drag = GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0 && GImGui->ActiveIdWindow == ImGui::GetCurrentWindow(); + + m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered || is_scrollbar_active_drag; imgui.end(); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 84cf311e57..7bae744098 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -589,6 +589,7 @@ private: bool m_toolpath_outside{ false }; ECursorType m_cursor_type; GLSelectionRectangle m_rectangle_selection; + bool m_navigator_dragging{ false }; //BBS:add plate related logic mutable std::vector m_hover_volume_idxs; @@ -916,6 +917,7 @@ public: void update_volumes_colors_by_extruder(); bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; } + bool has_mouse_capture() const; void render(bool only_init = false); bool is_rendering_enabled() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 7855ea92cc..1aaac99d40 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -442,7 +442,7 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { } } else if (m_dragging) { // when mouse cursor leave window than finish actual dragging operation - bool is_leaving = mouse_event.Leaving(); + bool is_leaving = mouse_event.Leaving() && !m_parent.has_mouse_capture(); // ORCA keep tracking mouse position while drag active and cursor not in window bounds if (mouse_event.Dragging()) { Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); auto ray = m_parent.mouse_ray(mouse_coord); From 6b5c8af1c8b48c7b75f1c82577ec824453305604 Mon Sep 17 00:00:00 2001 From: Ryan Hartman Date: Sun, 2 Aug 2026 21:03:59 -0600 Subject: [PATCH 12/23] Pin OpenSSL libdir so the bundled Python finds it (#15047) On Linux the bundled CPython silently links the system OpenSSL instead of the one built in deps/, and the dependency build then fails: install: cannot stat 'Modules/_ssl.cpython-312-x86_64-linux-gnu.so': No such file or directory The chain: * OpenSSL's linux-x86_64 target sets multilib=64, so 'make install_sw' installs the static libs to /lib64 while every other dependency in the prefix uses /lib. * CPython's --with-openssl= only ever emits -L/lib. It does not look in lib64, so -lssl resolves to the system OpenSSL. * gcc -shared does not error on unresolved symbols, so the link appears to succeed. _ssl.c was compiled against the bundled 1.1.1w headers, which map SSL_get1_peer_certificate onto the pre-3.0 SSL_get_peer_certificate -- a symbol OpenSSL 3.x removed. The module then fails to import: _ssl failed to import: undefined symbol: SSL_get_peer_certificate Could not build the ssl module! * With no _ssl built, 'make install' cannot stat it and the build stops. Passing --libdir=lib keeps the prefix single-layout, so CPython's -L/lib finds the bundled static libraries and links against the headers it was compiled with. CMake-based dependencies were unaffected throughout, because CMake's FindOpenSSL searches lib64 on its own; only CPython's autoconf path is sensitive to this. Affects any distribution where OpenSSL selects the lib64 layout, which is the Fedora, openSUSE and Arch families. Debian and Ubuntu are unaffected, which is why CI has not seen it. Verified on Arch (GCC 16.1.1, CMake 4.4.2): the dependency build completes and the bundled interpreter reports the bundled OpenSSL rather than the system one: $ deps/build/OrcaSlicer_dep/usr/local/libpython/bin/python3.12 \ -c 'import ssl; print(ssl.OPENSSL_VERSION)' OpenSSL 1.1.1w 11 Sep 2023 Not verified on macOS or Windows. The flag is accepted by OpenSSL's Configure on all platforms and Darwin targets do not set multilib, so it should be a no-op there, but CI is the check. --- deps/OpenSSL/OpenSSL.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/deps/OpenSSL/OpenSSL.cmake b/deps/OpenSSL/OpenSSL.cmake index 21a49b91b8..e43997265b 100644 --- a/deps/OpenSSL/OpenSSL.cmake +++ b/deps/OpenSSL/OpenSSL.cmake @@ -52,6 +52,14 @@ ExternalProject_Add(dep_OpenSSL CONFIGURE_COMMAND ${_conf_cmd} ${_cross_arch} "--openssldir=${DESTDIR}" "--prefix=${DESTDIR}" + # OpenSSL's linux-x86_64 target sets multilib=64, so it installs to + # /lib64 while every other dep uses /lib. CPython's + # --with-openssl only ever emits -L/lib, so it misses the bundled + # static libs and silently links the system OpenSSL instead -- which, + # against 1.1.1w headers, leaves _ssl.so with an undefined + # SSL_get_peer_certificate (removed in OpenSSL 3.x). Pin libdir so the + # prefix stays single-layout. + "--libdir=lib" ${_cross_comp_prefix_line} no-shared no-asm From 66d3f3f9c3fcd053acf4be4d7cfb8e858b91e674 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 3 Aug 2026 18:34:05 +0800 Subject: [PATCH 13/23] imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds (#15052) * imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds In single-line mode, click and drag already clamped y to the line's y-coordinate so the cursor would continue to follow the x-position when the mouse went off the top or bottom of the text. Multi-line mode did not clamp, so stb_text_locate_coord() would return 0 (above) or n (below), snapping the cursor to the very start or end of text and ignoring the x-coordinate entirely. Now both modes walk the row layout to compute the top of the first row (y_min) and bottom of the last row (y_max, minus half a line height to add tolerance for rounding), then clamp y to that range before passing it to stb_text_locate_coord(). This means dragging or clicking above the text now places the cursor on the first line at the x-coordinate, and dragging/clicking below places it on the last line at the x-coordinate, matching the single-line precedent. * Fix issue that cursor cannot be placed at the last empty line --- deps_src/imgui/imstb_textedit.h | 95 +++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/deps_src/imgui/imstb_textedit.h b/deps_src/imgui/imstb_textedit.h index 7644670975..3733bb2fa9 100644 --- a/deps_src/imgui/imstb_textedit.h +++ b/deps_src/imgui/imstb_textedit.h @@ -465,6 +465,57 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat STB_TEXTEDIT_LAYOUTROW(&r, str, 0); y = r.ymin; } + else + { + // In multi-line mode, clamp y to stay within the text vertical bounds. + // This lets the click still land at a valid location if the mouse is slightly + // above or below the text. + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + int i = 0; + float base_y = 0, y_min, y_max; + + // Get the first row to establish y_min and start the iteration + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + if (r.num_chars <= 0) + { + state->cursor = 0; + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + return; + } + y_min = r.ymin; + y_max = base_y + r.ymax; + i = r.num_chars; + base_y += r.baseline_y_delta; + + // Walk the remaining rows to find the bottom of the last row + while (i < n) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + break; + y_max = base_y + r.ymax; + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // If the text ends with a newline, account for the empty trailing line + // so the cursor can be placed on it + if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, n); + y_max = base_y + r.ymax; + } + + // Subtract half the last line height to avoid rounding issues when the mouse + // is just barely below the last line (keep cursor on the last line, not after the text) + y_max -= (r.ymax - r.ymin) * 0.5f; + + if (y < y_min) y = y_min; + if (y > y_max) y = y_max; + } state->cursor = stb_text_locate_coord(str, x, y); state->select_start = state->cursor; @@ -485,6 +536,50 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state STB_TEXTEDIT_LAYOUTROW(&r, str, 0); y = r.ymin; } + else + { + // In multi-line mode, clamp y to stay within the text vertical bounds. + // This lets the drag keep working if the mouse goes off the top or bottom of the text. + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + int i = 0; + float base_y = 0, y_min, y_max; + + // Get the first row to establish y_min and start the iteration + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + if (r.num_chars <= 0) + return; + y_min = r.ymin; + y_max = base_y + r.ymax; + i = r.num_chars; + base_y += r.baseline_y_delta; + + // Walk the remaining rows to find the bottom of the last row + while (i < n) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + break; + y_max = base_y + r.ymax; + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // If the text ends with a newline, account for the empty trailing line + // so the cursor can be placed on it + if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, n); + y_max = base_y + r.ymax; + } + + // Subtract half the last line height to avoid rounding issues when the mouse + // is just barely below the last line (keep cursor on the last line, not after the text) + y_max -= (r.ymax - r.ymin) * 0.5f; + + if (y < y_min) y = y_min; + if (y > y_max) y = y_max; + } if (state->select_start == state->select_end) state->select_start = state->cursor; From dbb991bf076e8b83c0b8f33fa03ecf7956b1ff1c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 3 Aug 2026 18:34:15 +0800 Subject: [PATCH 14/23] Fix gizmo being closed after releasing mouse outside the gizmo floating window (#15095) * Fix gizmo being closed after releasing mouse outside the gizmo floating window The left up event of a drag started on the gizmo floating window (e.g. selecting text in an input field) and released over the bed was treated as a click on the plate, which deselected the objects and closed the active gizmo. Add the ignore_left_up guard to the plate select branch, matching the deselect branch above. Co-Authored-By: Claude * Fix Emboss gizmo being closed after releasing mouse outside its floating window The Emboss gizmo has its own close-on-click-away handler (on_mouse_change_selection) that was not protected against left up events originating from ImGui windows, so the gizmo was still closed when a drag started on its floating window (e.g. selecting text in the input field) ended over the 3D scene. Expose the canvas's ignore_left_up state to gizmos and skip the close check for such releases. Co-Authored-By: Claude --------- Co-authored-by: Claude --- src/slic3r/GUI/GLCanvas3D.cpp | 4 +++- src/slic3r/GUI/GLCanvas3D.hpp | 4 ++++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 7 +++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a24c095ad6..110b6697ae 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4756,7 +4756,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) deselect_all(); } //BBS Select plate in this 3D canvas. - else if (evt.LeftUp() && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D) && !is_layers_editing_enabled()) + // The left up may come from an ImGui window (e.g. a drag started on the gizmo floating window and released over the bed), + // in which case it must not be treated as a click on the plate, otherwise the gizmo would be closed (see deselect_all below). + else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D) && !is_layers_editing_enabled()) { int hover_idx = m_hover_plate_idxs.front(); wxGetApp().plater()->select_plate_by_hover_id(hover_idx); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7bae744098..17497edf16 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1119,6 +1119,10 @@ public: void set_mouse_as_dragging() { m_mouse.dragging = true; } bool is_mouse_dragging() const { return m_mouse.dragging; } + // True when the current left up event comes from an ImGui window and was not processed by it + // (e.g. a drag that started on a gizmo floating window and was released over the 3D scene). + // Such a release is the end of an ImGui interaction, not a click on the scene. + bool is_mouse_left_up_ignored() const { return m_mouse.ignore_left_up; } double get_size_proportional_to_max_bed_size(double factor) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index feba37133a..ecf465afe7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -566,8 +566,11 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) void GLGizmoEmboss::on_mouse_change_selection(const wxMouseEvent &mouse_event) { - static bool was_dragging = true; - if ((mouse_event.LeftUp() || mouse_event.RightUp()) && !was_dragging) { + static bool was_dragging = true; + // The left up may be the end of a drag that started on the gizmo floating window (e.g. selecting + // text in the input field). Such a release is not a click on the scene and must not close the gizmo. + // (The flag is only set for left up events, so right up behavior is unchanged.) + if ((mouse_event.LeftUp() || mouse_event.RightUp()) && !was_dragging && !m_parent.is_mouse_left_up_ignored()) { // is hovered volume closest hovered? int hovered_idx = m_parent.get_first_hover_volume_idx(); if (hovered_idx < 0) From 74c4a7e450a745380108b55a1dc72233a2742f6d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 3 Aug 2026 22:25:50 +0800 Subject: [PATCH 15/23] Support printer specific filament profiles in the OrcaFilamentLibrary (#15101) * Support printer specific filament profiles in the Orca Filament Library --- scripts/orca_extra_profile_check.py | 10 ++- src/libslic3r/Preset.cpp | 6 +- .../libslic3r/test_preset_bundle_loading.cpp | 66 +++++++++++++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/scripts/orca_extra_profile_check.py b/scripts/orca_extra_profile_check.py index cdfc8544a4..07ce3d69d3 100644 --- a/scripts/orca_extra_profile_check.py +++ b/scripts/orca_extra_profile_check.py @@ -46,12 +46,16 @@ def no_duplicates_object_pairs_hook(pairs): return seen # NOTE: currently Orca expects compatible_printers to be a defined in every instantiation profile, inheritation is not supported in Profile page -def check_filament_compatible_printers(vendor_folder): +def check_filament_compatible_printers(vendor, vendor_folder): """ Checks JSON files in the vendor folder for missing or empty 'compatible_printers' when 'instantiation' is flagged as true. + In the OrcaFilamentLibrary 'compatible_printers' is optional: a profile without it is generic and + offered on every printer, while a profile that lists printers supersedes the generic one there. + Parameters: + vendor (str): The vendor name the folder belongs to. vendor_folder (str or Path): The directory to search for JSON profile files. Returns: @@ -115,7 +119,7 @@ def check_filament_compatible_printers(vendor_folder): for profile in profiles.values(): instantiation = str(profile['content'].get("instantiation", "")).lower() == "true" - if instantiation: + if instantiation and vendor != 'OrcaFilamentLibrary': try: compatible_printers = get_property(profile, "compatible_printers") if not compatible_printers or (isinstance(compatible_printers, list) and not compatible_printers): @@ -571,7 +575,7 @@ def main(): vendor_path = profiles_dir / vendor_name if args.check_filaments or not (args.check_materials and not args.check_filaments): - errors_found += check_filament_compatible_printers(vendor_path / "filament") + errors_found += check_filament_compatible_printers(vendor_name, vendor_path / "filament") if args.check_materials: new_errors, new_warnings = check_machine_default_materials(profiles_dir, vendor_name) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 2821bef0af..d5bf251d37 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -3784,12 +3784,14 @@ void PresetCollection::update_library_profile_excluded_from() } // Check all presets that has the same alias as the filament presets with empty compatible_printers in Orca Filament Library. + // A printer specific profile supersedes the generic one, no matter whether it lives in a vendor bundle or in the + // library itself. for (const Preset& preset : m_presets) { - if (preset.vendor == nullptr || preset.vendor->name == PresetBundle::ORCA_FILAMENT_LIBRARY) + if (preset.vendor == nullptr) continue; const auto* compatible_printers = dynamic_cast(preset.config.option("compatible_printers")); - // All profiles in concrete vendor profile shouldn't have empty compatible_printers, but here we check it for safety. + // Profiles with empty compatible_printers are the generic ones, they never supersede anything. if (compatible_printers == nullptr || compatible_printers->values.empty()) continue; auto itr = excluded_froms.find(preset.alias); diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 351535dd9d..c697c4461c 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -488,3 +488,69 @@ TEST_CASE("Plugin capability override keys are scoped per preset type", "[Preset } } +namespace { + +// A standalone filament collection that exposes the protected library masking builder, so the Orca +// Filament Library scenario can be set up without the full system-profile load pipeline. +struct LibraryFilamentTestCollection : public PresetCollection +{ + LibraryFilamentTestCollection() + : PresetCollection(Preset::TYPE_FILAMENT, Preset::filament_options(), + static_cast(FullPrintConfig::defaults())) + {} + using PresetCollection::update_library_profile_excluded_from; +}; + +} // namespace + +// Orca: a filament in the Orca Filament Library that names its compatible printers has to hide the generic +// library filament sharing its alias, the same way a vendor owned filament does. Otherwise both are compatible +// with that printer and the plater combo box lists the shared alias twice. +TEST_CASE("A printer specific filament supersedes the generic library filament with the same alias", "[Preset][Bundle]") +{ + LibraryFilamentTestCollection filaments; + PresetCollection printers(Preset::TYPE_PRINTER, Preset::printer_options(), + static_cast(FullPrintConfig::defaults())); + // The masking keys off the vendor name, which VendorProfile's constructor does not derive from the id. + VendorProfile library(PresetBundle::ORCA_FILAMENT_LIBRARY); + VendorProfile vendor("Vendor"); + library.name = PresetBundle::ORCA_FILAMENT_LIBRARY; + vendor.name = "Vendor"; + + auto add_filament = [&filaments](const VendorProfile &owner, const std::string &name, std::vector compatible_printers) { + Preset &preset = add_inmemory_preset(filaments, name); + preset.alias = "Generic ABS"; + preset.vendor = &owner; + preset.config.option("compatible_printers", true)->values = std::move(compatible_printers); + }; + + add_filament(library, "Generic ABS @System", {}); + add_filament(library, "Generic ABS @Printer A", { "Printer A" }); + add_filament(vendor, "Generic ABS @Printer B", { "Printer B" }); + + filaments.update_library_profile_excluded_from(); + + const Preset *generic = filaments.find_preset("Generic ABS @System"); + REQUIRE(generic != nullptr); + CHECK(generic->m_excluded_from.count("Printer A") == 1); + CHECK(generic->m_excluded_from.count("Printer B") == 1); + CHECK(generic->m_excluded_from.size() == 2); + + // A printer specific profile names printers, so it is never the one being hidden - not even by itself. + const Preset *specific = filaments.find_preset("Generic ABS @Printer A"); + REQUIRE(specific != nullptr); + CHECK(specific->m_excluded_from.empty()); + + // ...and the generic profile really drops out of the compatible set on the printer it is hidden from. + add_inmemory_preset(printers, "Printer A"); + add_inmemory_preset(printers, "Printer C"); + const Preset *printer_a = printers.find_preset("Printer A"); + const Preset *printer_c = printers.find_preset("Printer C"); + REQUIRE(printer_a != nullptr); + REQUIRE(printer_c != nullptr); + + const PresetWithVendorProfile generic_lib(*generic, &library); + CHECK_FALSE(is_compatible_with_printer(generic_lib, PresetWithVendorProfile(*printer_a, nullptr))); + CHECK(is_compatible_with_printer(generic_lib, PresetWithVendorProfile(*printer_c, nullptr))); +} + From 06ef58bad8cbe7b6f9ee930372001e20dc24c156 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Mon, 3 Aug 2026 09:29:00 -0500 Subject: [PATCH 16/23] test: replace the disabled convex_hull_2d test (#14892) test(libslic3r): replace the disabled convex_hull_2d test, closing #11269 The last "failing libslic3r test" from #11269 was the disabled SCENARIO("2D convex hull of sinking object", "[3mf][.]") in test_3mf.cpp. It checked ModelObject::convex_hull_2d for a sinking object against PrusaSlicer's reference hull, but Orca's convex_hull_2d does not clip geometry below the bed the way PrusaSlicer's its_convex_hull_2d_above does, so the reference never matched. The test also wrote a debug mesh to a hardcoded /tmp path and its comparison loop was inverted. Remove it and add tests/libslic3r/test_model.cpp characterizing convex_hull_2d on non-sinking transforms (identity and scale+offset), where the projected footprint is unambiguous. Homed in a Model test file since it exercises ModelObject, not 3MF. --- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_3mf.cpp | 61 ---------------------------------- tests/libslic3r/test_model.cpp | 40 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 61 deletions(-) create mode 100644 tests/libslic3r/test_model.cpp diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index dbc6c99f15..1ad299473c 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable(${_TEST_NAME}_tests test_stl.cpp test_meshboolean.cpp test_marchingsquares.cpp + test_model.cpp test_utils.cpp test_timeutils.cpp test_voronoi.cpp diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 1a082cd8e0..a6fe3ed460 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -509,64 +509,3 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") { boost::filesystem::remove_all(backup_dir); } } - -SCENARIO("2D convex hull of sinking object", "[3mf][.]") { - GIVEN("model") { - // load a model - Model model; - std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl"; - REQUIRE(load_stl(src_file.c_str(), &model)); - model.add_default_instances(); - - WHEN("model is rotated, scaled and set as sinking") { - ModelObject* object = model.objects[0]; - object->center_around_origin(false); - - // This outputs the same exact data as the Prusaslicer test - write_debug_stl("3mf/orca.ascii", object->volumes[0]->mesh()); - - // set instance's attitude so that it is rotated, scaled (and sinking? how is it sinking? the rotation? does it matter if it's sinking?) - ModelInstance* instance = object->instances[0]; - instance->set_rotation(X, -M_PI / 4.0); - instance->set_offset(Vec3d::Zero()); - instance->set_scaling_factor({ 2.0, 2.0, 2.0 }); - - // calculate 2D convex hull - auto trafo = instance->get_transformation().get_matrix(); - - // This matrix is the same exact matrix as the Prusaslicer test - CAPTURE(trafo); - Polygon hull_2d = object->convex_hull_2d(trafo); - - // But we get different hull_2d.points here (and somehow decimal numbers despite being int64_t values, but that's probabaly printing configuration somewhere -- Prusaslicer's prints out with newlines between the X&Y and not one between coordinates, which is about the worse possible output). - // I think it's something to do with PrusaSlicer ignoring everything under the Z plane, which makes sense from the results. - // See the comments added to ModelObject::convex_hull_2d for more information. - - // verify result - Points result = { - { -91501496, -15914144 }, - { 91501496, -15914144 }, - { 91501496, 4243 }, - { 78229680, 4246883 }, - { 56898100, 4246883 }, - { -85501496, 4242641 }, - { -91501496, 4243 } - }; - - THEN("2D convex hull should match with reference") { - // Allow 1um error due to floating point rounding. - bool res = hull_2d.points.size() == result.size(); - if (res) { - for (size_t i = 0; i < result.size(); ++ i) { - const Point &p1 = result[i]; - const Point &p2 = hull_2d.points[i]; - CHECK((std::abs(p1.x() - p2.x()) > 1 || std::abs(p1.y() - p2.y()) > 1)); - } - } - - CAPTURE(hull_2d.points); - REQUIRE(res); - } - } - } -} diff --git a/tests/libslic3r/test_model.cpp b/tests/libslic3r/test_model.cpp new file mode 100644 index 0000000000..3a580e3be2 --- /dev/null +++ b/tests/libslic3r/test_model.cpp @@ -0,0 +1,40 @@ +#include + +#include "libslic3r/Model.hpp" + +using namespace Slic3r; + +// convex_hull_2d does not clip geometry below the bed, so these cases avoid +// sinking transforms. +TEST_CASE("A part's 2D convex hull is its footprint projected onto the bed", "[Model]") +{ + Model model; + ModelObject* object = model.add_object(); + // Keep the cube's raw coordinates ([0,20] on every axis): the default + // add_volume re-centers the geometry, which would move the footprint. + object->add_volume(make_cube(20, 20, 20), ModelVolumeType::MODEL_PART, false); + + SECTION("identity transform yields the 20 mm square") { + const Polygon hull = object->convex_hull_2d(Geometry::Transformation{}.get_matrix()); + const BoundingBox bb = hull.bounding_box(); + CHECK(hull.size() == 4); + CHECK(bb.min.x() == scaled(0.)); + CHECK(bb.min.y() == scaled(0.)); + CHECK(bb.max.x() == scaled(20.)); + CHECK(bb.max.y() == scaled(20.)); + } + + SECTION("scaling and offset move and grow the footprint") { + Geometry::Transformation t; + t.set_scaling_factor({2, 2, 2}); // cube now spans [0,40] + t.set_offset({10, 5, 0}); // then shift +10 in X, +5 in Y + + const Polygon hull = object->convex_hull_2d(t.get_matrix()); + const BoundingBox bb = hull.bounding_box(); + CHECK(hull.size() == 4); + CHECK(bb.min.x() == scaled(10.)); + CHECK(bb.min.y() == scaled(5.)); + CHECK(bb.max.x() == scaled(50.)); + CHECK(bb.max.y() == scaled(45.)); + } +} From 7b404596e9eebef6c0595052604da5cc4f669139 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Mon, 3 Aug 2026 20:10:01 +0200 Subject: [PATCH 17/23] Add `Skip G-code config block` to exclude the config comments from G-code files (#12455) Add feature to skip CONFIG_BLOCK in G-code files --- src/libslic3r/GCode.cpp | 37 ++++++++++++++++++---------------- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 11 +++++++++- src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + tests/fff_print/test_print.cpp | 16 +++++++++++++++ 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f5db2e8349..ff2384a0a4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2884,6 +2884,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled, print.get_layered_nozzle_group_result()); const bool is_bbl_printers = print.is_BBL_printer(); + const bool skip_config_block = print.config().gcode_skip_config_block; const WipeTowerType wipe_tower_type = print.wipe_tower_type(); m_calib_config.clear(); // resets analyzer's tracking data @@ -3059,7 +3060,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // as configuration key / value pairs to be parsable by older versions of // PrusaSlicer G-code viewer. { - if (is_bbl_printers) { + if (is_bbl_printers && !skip_config_block) { file.write("; CONFIG_BLOCK_START\n"); std::string full_config; append_full_config(print, full_config); @@ -4086,23 +4087,25 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder) .c_str()); file.write("\n"); - file.write("; CONFIG_BLOCK_START\n"); - std::string full_config; - append_full_config(print, full_config); - if (!full_config.empty()) - file.write(full_config); + if (!skip_config_block) { + file.write("; CONFIG_BLOCK_START\n"); + std::string full_config; + append_full_config(print, full_config); + if (!full_config.empty()) + file.write(full_config); - // SoftFever: write compatiple info - int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); - file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); - file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str()); - file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0)); - file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value); - - //SF TODO -// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0); - - file.write("; CONFIG_BLOCK_END\n\n"); + // SoftFever: write compatiple info + int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); + file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); + file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str()); + file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0)); + file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value); + + //SF TODO +// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0); + + file.write("; CONFIG_BLOCK_END\n\n"); + } // !skip_config_block } file.write("\n"); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index d5bf251d37..2e33a36c83 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1404,7 +1404,7 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", "printable_area", "extruder_printable_area", "support_parallel_printheads", "parallel_printheads_count", "parallel_printheads_bed_exclude_areas", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", - "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs", + "gcode_skip_config_block", "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs", "single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type", "printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index cc991f91cc..ada05c4e9f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4259,6 +4259,15 @@ void PrintConfigDef::init_fff_params() def->readonly = false; def->set_default_value(new ConfigOptionEnum(gcfMarlinLegacy)); + def = this->add("gcode_skip_config_block", coBool); + def->label = L("Skip G-code config block"); + def->tooltip = L("Do not write the CONFIG_BLOCK (slicer configuration key/value pairs) into the G-code file. " + "This can help with printers whose firmware crashes when parsing these comment lines " + "(e.g. Anycubic go-klipper). Note: the G-code file will no longer contain slicer settings, " + "so importing it back into OrcaSlicer will not restore the configuration."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("pellet_modded_printer", coBool); def->label = L("Pellet Modded Printer"); def->tooltip = L("Enable this option if your printer uses pellets instead of filaments."); @@ -4292,7 +4301,7 @@ void PrintConfigDef::init_fff_params() "slow down."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(0)); - + //BBS def = this->add("infill_combination", coBool); def->label = L("Infill combination"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 90aa1adb3d..c1875e0288 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1547,7 +1547,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, gcode_add_line_number)) ((ConfigOptionBool, bbl_bed_temperature_gcode)) ((ConfigOptionEnum, gcode_flavor)) - + ((ConfigOptionBool, gcode_skip_config_block)) ((ConfigOptionFloat, time_cost)) ((ConfigOptionString, layer_change_gcode)) ((ConfigOptionString, time_lapse_gcode)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c8fa524ca5..c436d70a15 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5016,6 +5016,7 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("printer_structure", "printer_basic_information_advanced#printer-structure"); optgroup->append_single_option_line("gcode_flavor", "printer_basic_information_advanced#g-code-flavor"); + optgroup->append_single_option_line("gcode_skip_config_block", "printer_basic_information_advanced#skip-g-code-config-block"); optgroup->append_single_option_line("pellet_modded_printer", "printer_basic_information_advanced#pellet-modded-printer"); optgroup->append_single_option_line("bbl_use_printhost", "printer_basic_information_advanced#use-3rd-party-print-host"); optgroup->append_single_option_line("use_3mf"); diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index 9cb085f78b..6bff945fc3 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -338,6 +338,22 @@ TEST_CASE("G-code lists the resolved extrusion-width settings", "[Print]") CHECK(with_first_layer.find("; first layer extrusion width") != std::string::npos); } +// gcode_skip_config_block suppresses the resolved-settings block while leaving the +// header and executable blocks intact. +TEST_CASE("gcode_skip_config_block omits the resolved-settings comment block", "[Print]") +{ + const std::string gcode = slice({ cube(20) }, { + { "gcode_skip_config_block", true }, + { "gcode_comments", true }, + }); + CHECK(gcode.find("; CONFIG_BLOCK_START") == std::string::npos); + CHECK(gcode.find("; CONFIG_BLOCK_END") == std::string::npos); + CHECK(gcode.find("; layer_height =") == std::string::npos); + CHECK(gcode.find("; fill_density =") == std::string::npos); + CHECK(gcode.find("; HEADER_BLOCK_START") != std::string::npos); + CHECK(gcode.find("; EXECUTABLE_BLOCK_START") != std::string::npos); +} + // Custom G-code templates substitute placeholders during export. TEST_CASE("Custom G-code placeholders are substituted", "[Print]") { From ca7fbfb00751e403817dcbff5286550a5ce98efd Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Tue, 4 Aug 2026 00:02:48 +0300 Subject: [PATCH 18/23] Fix missing overhang wall when no partial counterbore bridge is generated (#15100) --- src/libslic3r/PerimeterGenerator.cpp | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index ad4d615807..2d6c993d78 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1977,7 +1977,7 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim ExPolygons unsupported = diff_ex(last, *this->lower_slices, ApplySafetyOffset::Yes); if (!unsupported.empty()) { //remove small overhangs - ExPolygons unsupported_filtered = offset2_ex(unsupported, double(-perimeter_spacing), double(perimeter_spacing)); + ExPolygons unsupported_filtered = opening_ex(unsupported, perimeter_spacing); if (!unsupported_filtered.empty()) { //to_draw.insert(to_draw.end(), last.begin(), last.end()); @@ -2090,35 +2090,40 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim //TODO: add other polys as holes inside this one (-margin) } else { // if(this->config->counterbore_hole_bridging.value == chbBridges) // Orca: Partial counterbore bridging is mask-based. Preserve the supported - // remainder (`last`) and use simplified BridgeDetector coverage to derive the + // remainder and use simplified BridgeDetector coverage to derive the // bridgeable counterbore span. The span is grown from supported material, - // shrunk back, stripped from `last`, and expanded back. It is then prevented - // from intruding deeper into `last` than the explicit anchor overlap. - // Finally, add the allowed anchor band from `last` then remove the + // shrunk back, stripped from the remaining normal surface, and expanded back. + // It is then prevented from intruding deeper into it than the explicit anchor overlap. + // Finally, add the allowed anchor band from it then remove the // narrow hole-side wall contact, which must remain unbridgeable. - last = diff_ex(last, unsupported_filtered, ApplySafetyOffset::Yes); + const ExPolygons remaining = diff_ex(last, unsupported_filtered, ApplySafetyOffset::Yes); ExPolygons bridgeable_filtered; + for (ExPolygon& poly : bridgeable) { poly.simplify(perimeter_spacing, &bridgeable_filtered); } bridgeable_filtered = opening_ex(bridgeable_filtered, ext_perimeter_width); // Get rid of coarseness of the resulted bridgeable area by using the original supported area as reference. - // This is to avoid keeping tiny bridgeable areas that are far from the supported area, or protrude into it. - bridgeable_filtered = union_ex(offset_ex(last, perimeter_spacing), bridgeable_filtered); + // This is to avoid keeping tiny bridgeable areas that are far from the supported area, or protrude into it. + bridgeable_filtered = union_ex(offset_ex(remaining, perimeter_spacing), bridgeable_filtered); bridgeable_filtered = offset_ex(bridgeable_filtered, -perimeter_spacing); - bridgeable_filtered = diff_ex(bridgeable_filtered, last, ApplySafetyOffset::Yes); + bridgeable_filtered = diff_ex(bridgeable_filtered, remaining, ApplySafetyOffset::Yes); bridgeable_filtered = opening_ex(bridgeable_filtered, perimeter_spacing); // filter noise from the diff_ex bridgeable_filtered = offset_ex(bridgeable_filtered, perimeter_spacing); // restore the size to the original bridgeable area // Safety measure: Keep the bridge mask from intruding deeper into the - // supported anchor region (`last`) than the explicit anchor overlap. - bridgeable_filtered = diff_ex(bridgeable_filtered, offset_ex(last, -bridge_anchor_offset)); + // supported anchor region than the explicit anchor overlap. + bridgeable_filtered = diff_ex(bridgeable_filtered, offset_ex(remaining, -bridge_anchor_offset)); - ExPolygons bridge_anchor_areas = intersection_ex(last, offset_ex(unsupported_filtered, bridge_anchor_offset)); + ExPolygons bridge_anchor_areas = intersection_ex(remaining, offset_ex(unsupported_filtered, bridge_anchor_offset)); unsupported_filtered = union_ex(bridgeable_filtered, bridge_anchor_areas); // add bridge anchor unsupported_filtered = opening_ex(unsupported_filtered, bridge_anchor_offset); // remove anchor area from hole-side walls, it must remain unbridgeable + + // update 'last' only if we have a valid bridgeable area, otherwise we will lose the original unsupported area + if (!unsupported_filtered.empty()) + last = remaining; // TODO: Fix the case with thin outer walls around the bridge (1~2 walls) where classic wall // might generate two walls in a tiny space or non at all if "Detect thin walls" is not activated } From 40eab797c6a60a5949c0f92d00798da414c4b44a Mon Sep 17 00:00:00 2001 From: yw4z Date: Tue, 4 Aug 2026 03:45:31 +0300 Subject: [PATCH 19/23] match em_unit value for on_dpi_change for linux (#15043) * Update GUI_Utils.hpp * Update GUI_Utils.hpp --- src/slic3r/GUI/GUI_Utils.hpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 890e8b9e1c..c93c40b066 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -113,14 +113,7 @@ public: update_dark_ui(this); #endif - // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). - // So, calculate the m_em_unit value from the font size, as before -#if !defined(__WXGTK__) - m_em_unit = std::max(10, 10.0f * m_scale_factor); -#else - // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. - m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); -#endif // __WXGTK__ + update_em_unit(); // recalc_font(); @@ -235,6 +228,19 @@ private: // m_em_unit = metrics.averageWidth; // } + // update em_unit value for new window font + void update_em_unit() + { + // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). + // So, calculate the m_em_unit value from the font size, as before +#if !defined(__WXGTK__) + m_em_unit = std::max(10, 10.0f * m_scale_factor); +#else + // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. + m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); +#endif // __WXGTK__ + } + // check if new scale is differ from previous bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; } @@ -247,8 +253,7 @@ private: // set normal application font as a current window font m_normal_font = this->GetFont(); - // update em_unit value for new window font - m_em_unit = std::max(10, 10.0f * m_scale_factor); + update_em_unit(); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); From 59155f26ac05d38817835d408a435f207b251477 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Tue, 4 Aug 2026 10:56:15 -0300 Subject: [PATCH 20/23] Build Arch Fix (#15107) Arch Fix --- src/libslic3r/AABBTreeLines.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/AABBTreeLines.hpp b/src/libslic3r/AABBTreeLines.hpp index 97ad1bdf44..52c4cdf545 100644 --- a/src/libslic3r/AABBTreeLines.hpp +++ b/src/libslic3r/AABBTreeLines.hpp @@ -31,8 +31,9 @@ namespace AABBTreeLines { inline VectorType closest_point_to_origin(size_t primitive_index, ScalarType& squared_distance) const { Vec nearest_point; + Vec cast_origin = origin.template cast(); const LineType& line = lines[primitive_index]; - squared_distance = line_alg::distance_to_squared(line, origin.template cast(), &nearest_point); + squared_distance = line_alg::distance_to_squared(line, cast_origin, &nearest_point); return nearest_point.template cast(); } }; From 82759d3899745efbacc10e5bf9737cc5b23097dd Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Tue, 4 Aug 2026 09:01:45 -0500 Subject: [PATCH 21/23] fix: make the error dialog caret point at the character it's blaming (#14886) * fix: make the error dialog caret point at the character it's blaming Custom G-code parse errors print the offending line with a '^' under the character that broke, positioned with spaces so it only lines up in a fixed-width font. Since v2.3.2 these dialogs rendered entirely in the proportional UI font, so the caret drifted left of its column and landed on unrelated text. Render only the code excerpts (the offending source line and its caret) in the fixed-width face, leaving the surrounding prose in the UI font, and reserve the horizontal scrollbar's height so a long line does not clip. Rename the flag to has_code_excerpts to match what it now means. Fixes #14869 * refactor(GUI): use instead of for error excerpts wxHTML maps , , and to the same fixed-width handler, so this renders identically. is the non-deprecated tag and matches what the original code used. * fix(GUI): align the error caret with real spaces, not   The caret line was padded with   so its spaces would survive inline HTML. wxHTML measures every glyph by its font extent, so where the fixed font lacks a U+00A0 glyph the fallback renders it about twice as wide, and the all-  caret line outran the source, drifting the ^ to the right. Wrap the excerpts in a small tag, registered on the dialog's own parser, that switches on wxHTML literal-whitespace mode so the caret uses real spaces that match the source column in any font. It sits inside for the fixed face;
 would do both but forces a blank line above it.

---------

Co-authored-by: Noisyfox 
---
 src/libslic3r/PlaceholderParser.cpp |   2 +
 src/slic3r/GUI/GUI.cpp              |   8 +-
 src/slic3r/GUI/GUI.hpp              |  10 +--
 src/slic3r/GUI/MsgDialog.cpp        | 124 ++++++++++++++++++++++++----
 src/slic3r/GUI/MsgDialog.hpp        |   6 +-
 5 files changed, 120 insertions(+), 30 deletions(-)

diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp
index e3a4037590..3e29e0c172 100644
--- a/src/libslic3r/PlaceholderParser.cpp
+++ b/src/libslic3r/PlaceholderParser.cpp
@@ -1791,6 +1791,8 @@ namespace client
             // from UTF8 to UTF16 don't bail out.
             msg += boost::nowide::narrow(boost::nowide::widen(error_line));
             msg += '\n';
+            // The error dialog (MsgDialog.cpp) renders this excerpt monospaced. It recognizes a source
+            // line directly above a caret line of spaces and a single '^'.
             for (size_t i = 0; i < error_pos; ++ i)
                 msg += ' ';
             msg += "^\n";
diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp
index 554ecd4a4e..29f8fc9749 100644
--- a/src/slic3r/GUI/GUI.cpp
+++ b/src/slic3r/GUI/GUI.cpp
@@ -256,18 +256,18 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
 	}
 }
 
-void show_error(wxWindow* parent, const wxString& message, bool monospaced_font)
+void show_error(wxWindow* parent, const wxString& message, bool has_code_excerpts)
 {
     wxGetApp().CallAfter([=] {
-        ErrorDialog msg(parent, message, monospaced_font);
+        ErrorDialog msg(parent, message, has_code_excerpts);
         msg.ShowModal();
     });
 }
 
-void show_error(wxWindow* parent, const char* message, bool monospaced_font)
+void show_error(wxWindow* parent, const char* message, bool has_code_excerpts)
 {
 	assert(message);
-	show_error(parent, wxString::FromUTF8(message), monospaced_font);
+	show_error(parent, wxString::FromUTF8(message), has_code_excerpts);
 }
 
 void show_error_id(int id, const std::string& message)
diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp
index 357fd20a97..db882b79cf 100644
--- a/src/slic3r/GUI/GUI.hpp
+++ b/src/slic3r/GUI/GUI.hpp
@@ -40,11 +40,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
 // Change option value in config
 void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
 
-// If monospaced_font is true, the error message is displayed using html 
tags, -// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. -void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); -void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); -inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } +// If has_code_excerpts is true, code excerpts (a source line and the caret line below it) render +// monospaced so the caret aligns. Used for placeholder-parser errors. +void show_error(wxWindow* parent, const wxString& message, bool has_code_excerpts = false); +void show_error(wxWindow* parent, const char* message, bool has_code_excerpts = false); +inline void show_error(wxWindow* parent, const std::string& message, bool has_code_excerpts = false) { show_error(parent, message.c_str(), has_code_excerpts); } void show_error_id(int id, const std::string& message); // For Perl void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); void show_info(wxWindow* parent, const char* message, const char* title = nullptr); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index ebf4db6846..7f1effd162 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -9,8 +9,13 @@ #include #include #include +#include + +#include #include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" @@ -229,12 +234,82 @@ void MsgDialog::finalize() } +// A placeholder-parser caret line, pointing at the column where parsing failed. +static bool is_caret_line(const std::string &line) +{ + return std::count(line.begin(), line.end(), '^') == 1 && + std::all_of(line.begin(), line.end(), [](char c) { return c == ' ' || c == '^'; }); +} + +// Tag each line as a code excerpt (a caret line or the source line above one) that must stay +// monospaced for the '^' to align. +static std::vector> classify_code_lines(const std::string &msg) +{ + std::vector lines; + boost::split(lines, msg, boost::is_any_of("\n")); + for (std::string &line : lines) + if (!line.empty() && line.back() == '\r') + line.pop_back(); + + std::vector> tagged; + tagged.reserve(lines.size()); + for (size_t i = 0; i < lines.size(); ++i) { + bool is_code = is_caret_line(lines[i]) || (i + 1 < lines.size() && is_caret_line(lines[i + 1])); + tagged.emplace_back(std::move(lines[i]), is_code); + } + return tagged; +} + +// Keeps whitespace literal so the caret's leading spaces survive. +// Used inside , which supplies the fixed face.
 does both but adds a blank line above it.
+class CodeExcerptTagHandler : public wxHtmlWinTagHandler
+{
+public:
+    wxString GetSupportedTags() override { return wxT("EXCERPT"); }
+    bool     HandleTag(const wxHtmlTag &tag) override
+    {
+        const wxHtmlWinParser::WhitespaceMode ws = m_WParser->GetWhitespaceMode();
+        m_WParser->SetWhitespaceMode(wxHtmlWinParser::Whitespace_Pre);
+        ParseInner(tag);
+        m_WParser->SetWhitespaceMode(ws);
+        return true;
+    }
+};
+
+// Render the message as HTML, monospacing only the code excerpts.
+static std::string format_parser_error_html(const std::string &msg)
+{
+    std::string out;
+    for (const auto &[text, is_code] : classify_code_lines(msg)) {
+        if (!out.empty()) out += "
"; // join, not trail; a trailing
forces a scrollbar + std::string escaped = xml_escape(text); + if (is_code) + out += "" + escaped + ""; + else + out += escaped; + } + return out; +} + +// Measure each line in the font it will render in, so the dialog fits the longest line without slack. +static wxSize measure_mixed_text(wxWindow *parent, const std::string &msg, const wxFont &prose_font, const wxFont &code_font) +{ + wxClientDC dc(parent); + int width = 0, height = 0; + for (const auto &[text, is_code] : classify_code_lines(msg)) { + dc.SetFont(is_code ? code_font : prose_font); + width = std::max(width, dc.GetTextExtent(wxString::FromUTF8(text.c_str())).GetWidth()); + height += dc.GetCharHeight(); + } + return wxSize(width, height); +} + // Text shown as HTML, so that mouse selection and Ctrl-V to copy will work. static void add_msg_content(wxWindow *parent, wxBoxSizer *content_sizer, wxString msg, - bool monospaced_font = false, - bool is_marked_msg = false, + bool has_code_excerpts = false, + bool is_marked_msg = false, const wxString &link_text = "", std::function link_callback = nullptr) { @@ -243,7 +318,7 @@ static void add_msg_content(wxWindow *parent, // count lines in the message int msg_lines = 0; - if (!monospaced_font) { + if (!has_code_excerpts) { int line_len = 55;// count of symbols in one line int start_line = 0; for (auto i = msg.begin(); i != msg.end(); ++i) { @@ -300,13 +375,23 @@ static void add_msg_content(wxWindow *parent, page_size = wxSize(info_width, page_height); } else { - wxClientDC dc(parent); - dc.SetFont(font); // ORCA without this it calculates bigger size - wxSize msg_sz = dc.GetMultiLineTextExtent(msg) + parent->FromDIP(wxSize(10,5)); // added extra spacing to prevent wrapping + wxSize msg_sz; + if (has_code_excerpts) { + msg_sz = measure_mixed_text(parent, msg.ToUTF8().data(), font, monospace); + } else { + wxClientDC dc(parent); + dc.SetFont(font); // ORCA without this it calculates bigger size + msg_sz = dc.GetMultiLineTextExtent(msg); + } + msg_sz += parent->FromDIP(wxSize(10,5)); // added extra spacing to prevent wrapping - page_size = wxSize(std::min(msg_sz.GetX(), info_width), std::min(msg_sz.GetY(), info_width)); + int page_height = msg_sz.GetY(); + // Reserve the horizontal scrollbar's height, or it clips the last line. + if (msg_sz.GetX() > info_width) + page_height += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y, parent); + page_size = wxSize(std::min(msg_sz.GetX(), info_width), std::min(page_height, info_width)); // Extra line breaks in message dialog - if (link_text.IsEmpty() && !link_callback && is_marked_msg == false) {//for common text + if (link_text.IsEmpty() && !link_callback && is_marked_msg == false && !has_code_excerpts) {//for common text html->Destroy(); if (msg_sz.GetX() < info_width) {//No need for line breaks info_width = msg_sz.GetX(); @@ -337,12 +422,15 @@ static void add_msg_content(wxWindow *parent, } html->SetMinSize(page_size); - std::string msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg); - boost::replace_all(msg_escaped, "\r\n", "
"); - boost::replace_all(msg_escaped, "\n", "
"); - if (monospaced_font) - // Code formatting will be preserved. This is useful for reporting errors from the placeholder parser. - msg_escaped = std::string("
") + msg_escaped + "
"; + std::string msg_escaped; + if (has_code_excerpts) { + html->GetParser()->AddTagHandler(new CodeExcerptTagHandler()); + msg_escaped = format_parser_error_html(msg.ToUTF8().data()); + } else { + msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg); + boost::replace_all(msg_escaped, "\r\n", "
"); + boost::replace_all(msg_escaped, "\n", "
"); + } if (!link_text.IsEmpty() && link_callback) { msg_escaped += "" + std::string(link_text.ToUTF8().data()) + ""; @@ -360,15 +448,15 @@ static void add_msg_content(wxWindow *parent, // ErrorDialog -ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool monospaced_font) +ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool has_code_excerpts) : MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_FULL_NAME), wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_FULL_NAME), wxOK) , msg(temp_msg) { - add_msg_content(this, content_sizer, msg, monospaced_font); + add_msg_content(this, content_sizer, msg, has_code_excerpts); - // Use a small bitmap with monospaced font, as the error text will not be wrapped. - logo->SetBitmap(create_scaled_bitmap("OrcaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : /*1*/64)); + // Use a small bitmap for code excerpts, which cannot wrap and so need the width. + logo->SetBitmap(create_scaled_bitmap("OrcaSlicer_192px_grayscale.png", this, has_code_excerpts ? 48 : /*1*/64)); SetMaxSize(MSG_DLG_MAX_SIZE); diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index 174d734336..90fd160310 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -106,9 +106,9 @@ protected: class ErrorDialog : public MsgDialog { public: - // If monospaced_font is true, the error message is displayed using html
tags, - // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. - ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool courier_font); + // If has_code_excerpts is true, code excerpts (a source line and the caret line below it) render + // monospaced so the caret aligns. Used for placeholder-parser errors. + ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool has_code_excerpts); ErrorDialog(ErrorDialog &&) = delete; ErrorDialog(const ErrorDialog &) = delete; ErrorDialog &operator=(ErrorDialog &&) = delete; From 1d078e005a1bff17f05745d7672a0bd1c5f7cc60 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Tue, 4 Aug 2026 11:37:05 -0300 Subject: [PATCH 22/23] Mouse ear Wiki redirect (#15115) Based in https://github.com/OrcaSlicer/OrcaSlicer/pull/15015 and https://github.com/OrcaSlicer/OrcaSlicer_WIKI/pull/323 --- src/slic3r/GUI/Tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c436d70a15..0c38977c74 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3077,7 +3077,7 @@ void TabPrint::build() optgroup->append_single_option_line("combine_brims", "others_settings_brim#combine-brims"); optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle"); optgroup->append_single_option_line("brim_ears_detection_length", "others_settings_brim#ear-detection-radius"); - optgroup->append_single_option_line("brim_ears_outer_only"); + optgroup->append_single_option_line("brim_ears_outer_only", "others_settings_brim#brim-ears-outer-only"); optgroup = page->new_optgroup(L("Special mode"), L"param_special"); optgroup->append_single_option_line("slicing_mode", "others_settings_special_mode#slicing-mode"); From 0051768206bd3ba082e75e7a09d5906d438dedfd Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 5 Aug 2026 00:09:46 +0800 Subject: [PATCH 23/23] Smooth out the spiral lift when arc fitting is disabled (#15118) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linear approximation used a heuristic segment count clamped to 4..16, so the lift ran as a coarse polygon. Every vertex is a direction change large enough to hit the firmware's jerk limit, forcing a decelerate/accelerate at each corner — the lift micro-stutters instead of running at speed. The segment count now comes from the chord deviation against the slicing resolution, reusing Geometry::ArcWelder::arc_discretization_steps, which keeps the turn at each vertex shallow enough for the firmware to carry speed through the whole move. Points are emitted through GCodeG1Formatter so they carry the same quantization as the rest of the G-code, and the move comment now trails the feedrate line to match _travel_to_z and the G2/G3 branch. No change when arc fitting is enabled. --- src/libslic3r/GCodeWriter.cpp | 52 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index e3d1c30362..0e80cc1fb7 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -3,6 +3,7 @@ #include "I18N.hpp" #include "PrintConfig.hpp" #include "ClipperUtils.hpp" +#include "Geometry/ArcWelder.hpp" #include "Line.hpp" #include #include @@ -1018,45 +1019,48 @@ std::string GCodeWriter::_spiral_travel_to_z(double z, const Vec2d &ij_offset, c } if (!this->config.enable_arc_fitting) { // Orca: if arc fitting is disabled, approximate the arc with small linear segments - std::ostringstream oss; const double z_start = m_pos(2); // starting Z height - // -------------------------------------------------------------------- - // Determine number of segments based on Resolution - // -------------------------------------------------------------------- - const double ref_resolution = 0.01; // reference resolution in mm - const double ref_segments = 8.0; // reference number of segments at reference resolution - - // number of linear segments to use for approximating the arc, clamp between 4 and 16 - const int segments = std::clamp(int(std::round(ref_segments * (ref_resolution / m_resolution))), 4, 16); - // -------------------------------------------------------------------- - const double px = m_pos(0) - m_x_offset; // take plate offset into consideration const double py = m_pos(1) - m_y_offset; // take plate offset into consideration const double cx = px + ij_offset(0); // center x const double cy = py + ij_offset(1); // center y const double radius = ij_offset.norm(); // radius + + // Number of linear segments approximating the circle, chosen so that a chord never deviates + // from the true arc by more than the slicing resolution. A resolution of 0 means "no + // simplification", which has no finite segment count, so it takes the upper bound. + constexpr size_t min_segments = 8; // keep a small spiral visibly round + constexpr size_t max_segments = 128; // bound the emitted G-code + const int segments = int(m_resolution > 0. ? + std::clamp(Geometry::ArcWelder::arc_discretization_steps(radius, 2. * M_PI, m_resolution), min_segments, max_segments) : + max_segments); + const double a0 = std::atan2(py - cy, px - cx); // start angle - const double delta = 2.0 * M_PI; // CCW full circle - if (full_gcode_comment) - oss << ";" << comment << "\n"; + auto emit_point = [&output](const Vec3d &point) { + GCodeG1Formatter w; + w.emit_xyz(point); + output += w.string(); + }; - oss << "G1 F" << (speed * 60.0) << "\n"; // set feedrate + output.reserve(size_t(segments) * 40); // ~40 characters per emitted G1 line + + GCodeG1Formatter w; // set feedrate + w.emit_f(speed * 60.0); + w.emit_comment(GCodeWriter::full_gcode_comment, comment); + output += w.string(); // approximate the arc with small linear segments (without the last point which is added later to ensure exactness) for (int i = 1; i < segments; ++i) { - double t = double(i) / segments; // parametric position along arc - double a = a0 + delta * t; // CCW arc param - double x = cx + radius * std::cos(a); // point on circle - double y = cy + radius * std::sin(a); // point on circle - double zz = z_start + (z - z_start) * t; // interpolated Z height - - oss << "G1 X" << x << " Y" << y << " Z" << zz << "\n"; + const double t = double(i) / segments; // parametric position along arc + const double a = a0 + 2. * M_PI * t; // CCW arc param, full circle + emit_point(Vec3d(cx + radius * std::cos(a), // point on circle + cy + radius * std::sin(a), + z_start + (z - z_start) * t)); // interpolated Z height } - oss << "G1 X" << px << " Y" << py << " Z" << z << "\n"; // final point to ensure exactness - output = oss.str(); + emit_point(Vec3d(px, py, z)); // final point to ensure exactness } else { // Orca: if arc fitting is enabled emit a G2/G3 command for the spiral lift output = std::string("G17") + (full_gcode_comment ? " ; XY plane for arc\n" : "\n");