From 07173a8de41a4974d0e67052a4b5b1b0068b6923 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 28 Apr 2026 22:36:30 +0800 Subject: [PATCH 001/127] Remove unused facets --- src/libslic3r/Model.cpp | 6 +----- src/libslic3r/Model.hpp | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index e3b2ada837..ef5ef6dbe6 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2714,11 +2714,7 @@ size_t ModelVolume::split(unsigned int max_extruders) this->source = ModelVolume::Source(); // BBS: reset facet annotations - this->mmu_segmentation_facets.reset(); - this->exterior_facets.reset(); - this->supported_facets.reset(); - this->seam_facets.reset(); - this->fuzzy_skin_facets.reset(); + this->reset_extra_facets(); } else this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(mesh))); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 5974ca4cd6..3fd66f5f69 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -881,9 +881,6 @@ public: mutable std::vector mmuseg_extruders; mutable Timestamp mmuseg_ts; - // List of exterior faces - FacetsAnnotation exterior_facets; - // Is set only when volume is Embossed Text type // Contain information how to re-create volume std::optional text_configuration; From ded2e72dcc47bc7cb38f1a50ac1605e1179f77db Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 28 Apr 2026 22:47:41 +0800 Subject: [PATCH 002/127] Refine code --- src/libslic3r/CutUtils.cpp | 8 ++++---- src/libslic3r/TriangleMeshSlicer.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 8611ec302d..eff267588c 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -566,17 +566,17 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran }; // cut by upper plane - - const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; { + const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; + cut(tmp_object, cut_matrix_upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); } // cut by lower plane - - const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; { + const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; + cut(tmp_object, cut_matrix_lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); } diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 150c456b8b..2c1c0da23f 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -2348,7 +2348,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u IntersectionLines upper_lines, lower_lines; std::vector upper_slice_vertices, lower_slice_vertices; std::vector facets_edge_ids = its_face_edge_ids(mesh); - std::map section_vertices_map; + std::map section_vertices_map; // vertices on the cut plane for (int facet_idx = 0; facet_idx < int(mesh.indices.size()); ++ facet_idx) { const stl_triangle_vertex_indices &facet = mesh.indices[facet_idx]; From 24458ba5a20048394175ba9adb74f5582cfa54cf Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 4 May 2026 20:32:39 +0800 Subject: [PATCH 003/127] Remapping the paintings after cut --- src/libslic3r/CutUtils.cpp | 68 ++++++- src/libslic3r/Model.hpp | 1 + src/libslic3r/TriangleSelector.cpp | 292 +++++++++++++++++++++++++++-- src/libslic3r/TriangleSelector.hpp | 12 +- 4 files changed, 349 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index eff267588c..7979dc4095 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -8,11 +8,39 @@ #include "ObjectID.hpp" #include +#include namespace Slic3r { using namespace Geometry; +// Saved painting data for remapping after mesh cutting. +struct SavedPainting { + indexed_triangle_set its; // Original mesh transformed to cut space + TriangleSelector::TriangleSplittingData supported; + TriangleSelector::TriangleSplittingData seam; + TriangleSelector::TriangleSplittingData mmu; + TriangleSelector::TriangleSplittingData fuzzy; +}; + +// Remap painting data from saved source to a cut result mesh, and set on a volume. +static void remap_and_set_painting(ModelVolume* vol, const indexed_triangle_set& cut_its, + const SavedPainting& saved) +{ + auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data, + FacetsAnnotation& target_facets) { + if (src_data.bitstream.empty()) + return; + auto result = TriangleSelector::remap_painting(saved.its, src_data, cut_its); + if (!result.bitstream.empty()) + target_facets.set_data(result); + }; + remap_one(saved.supported, vol->supported_facets); + remap_one(saved.seam, vol->seam_facets); + remap_one(saved.mmu, vol->mmu_segmentation_facets); + remap_one(saved.fuzzy, vol->fuzzy_skin_facets); +} + static void apply_tolerance(ModelVolume* vol) { ModelVolume::CutInfo& cut_info = vol->cut_info; @@ -179,7 +207,8 @@ static void process_modifier_cut(ModelVolume* volume, const Transform3d& instanc } static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, + const SavedPainting* saved_painting = nullptr) { // Perform cut TriangleMesh upper_mesh, lower_mesh; @@ -189,18 +218,28 @@ static void process_solid_part_cut(ModelVolume* volume, const Transform3d& insta if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); + if (saved_painting && !upper_mesh.empty()) + remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting); if (!lower_mesh.empty()) { add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); + if (saved_painting) + remap_and_set_painting(upper->volumes.back(), lower_mesh.its, *saved_painting); upper->volumes.back()->cut_info.is_from_upper = false; } return; } - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { add_cut_volume(upper_mesh, upper, volume, cut_matrix); + if (saved_painting && !upper_mesh.empty()) + remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting); + } - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { add_cut_volume(lower_mesh, lower, volume, cut_matrix); + if (saved_painting) + remap_and_set_painting(lower->volumes.back(), lower_mesh.its, *saved_painting); + } } static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, @@ -321,6 +360,26 @@ const ModelObjectPtrs& Cut::perform_with_plane() const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset()); for (ModelVolume* volume : mo->volumes) { + // Save painting data before reset_extra_facets() discards it. + // Only for model parts that will be cut (not modifiers/connectors). + std::optional saved_painting; + if (volume->is_model_part() && !volume->mesh().empty()) { + SavedPainting sp; + // Get mesh in cut space (same transform as process_volume_cut applies) + TriangleMesh mesh(volume->mesh()); + const auto volume_matrix = volume->get_matrix(); + mesh.transform(inverse_cut_matrix * instance_matrix * volume_matrix, true); + mesh.transform(m_cut_matrix); + sp.its = std::move(mesh.its); + sp.supported = volume->supported_facets.get_data(); + sp.seam = volume->seam_facets.get_data(); + sp.mmu = volume->mmu_segmentation_facets.get_data(); + sp.fuzzy = volume->fuzzy_skin_facets.get_data(); + if (!sp.supported.bitstream.empty() || !sp.seam.bitstream.empty() || + !sp.mmu.bitstream.empty() || !sp.fuzzy.bitstream.empty()) + saved_painting = std::move(sp); + } + volume->reset_extra_facets(); if (!volume->is_model_part()) { @@ -330,7 +389,8 @@ const ModelObjectPtrs& Cut::perform_with_plane() process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels); } else if (!volume->mesh().empty()) - process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower); + process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, + saved_painting ? &*saved_painting : nullptr); } // Post-process cut parts diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 3fd66f5f69..302bf47935 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -731,6 +731,7 @@ public: void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } } void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } } const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; } + void set_data(const TriangleSelector::TriangleSplittingData &data) { m_data = data; this->touch(); } bool set(const TriangleSelector& selector); indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const; // BBS diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index a6d19f505c..6368955fce 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -1,9 +1,11 @@ #include "TriangleSelector.hpp" #include "Model.hpp" +#include "AABBTreeIndirect.hpp" #include #include #include +#include #include #ifndef NDEBUG @@ -168,24 +170,25 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si this->special_side_idx = char(special_side_idx); } +// Real-time collision detection, Ericson, Chapter 3.4 +inline Vec3f barycentric(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +{ + std::array v = {p2 - p1, p3 - p1, pt - p1}; + float d00 = v[0].dot(v[0]); + float d01 = v[0].dot(v[1]); + float d11 = v[1].dot(v[1]); + float d20 = v[2].dot(v[0]); + float d21 = v[2].dot(v[1]); + float denom = d00 * d11 - d01 * d01; + + Vec3f barycentric_cords(1.f, (d11 * d20 - d01 * d21) / denom, (d00 * d21 - d01 * d20) / denom); + barycentric_cords.x() = barycentric_cords.x() - barycentric_cords.y() - barycentric_cords.z(); + return barycentric_cords; +} + inline bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) { - // Real-time collision detection, Ericson, Chapter 3.4 - auto barycentric = [&pt, &p1, &p2, &p3]() -> Vec3f { - std::array v = {p2 - p1, p3 - p1, pt - p1}; - float d00 = v[0].dot(v[0]); - float d01 = v[0].dot(v[1]); - float d11 = v[1].dot(v[1]); - float d20 = v[2].dot(v[0]); - float d21 = v[2].dot(v[1]); - float denom = d00 * d11 - d01 * d01; - - Vec3f barycentric_cords(1.f, (d11 * d20 - d01 * d21) / denom, (d00 * d21 - d01 * d20) / denom); - barycentric_cords.x() = barycentric_cords.x() - barycentric_cords.y() - barycentric_cords.z(); - return barycentric_cords; - }; - - Vec3f barycentric_cords = barycentric(); + Vec3f barycentric_cords = barycentric(pt, p1, p2, p3); return std::all_of(begin(barycentric_cords), end(barycentric_cords), [](float cord) { return 0.f <= cord && cord <= 1.0; }); } @@ -935,7 +938,7 @@ bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i32 &n if (triangle_splitting) split_triangle(facet_idx, neighbors); - else if (!m_triangles[facet_idx].is_split()) + if (!m_triangles[facet_idx].is_split()) m_triangles[facet_idx].set_state(type); tr = &m_triangles[facet_idx]; // might have been invalidated by split_triangle(). @@ -2208,4 +2211,259 @@ std::vector TriangleSelector::extract_used_facet_states(con return out; } +inline bool segments_intersect_proj( + const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4, const std::function(const Vec3f&)>& proj) +{ + auto cross2d = [](float ax, float ay, float bx, float by) -> float { return ax * by - ay * bx; }; + auto [u1, v1] = proj(p1); + auto [u2, v2] = proj(p2); + auto [u3, v3] = proj(p3); + auto [u4, v4] = proj(p4); + float ru = u2 - u1, rv = v2 - v1; + float su = u4 - u3, sv = v4 - v3; + float denom = cross2d(ru, rv, su, sv); + if (std::abs(denom) < 1e-10f) + return false; + float dpu = u3 - u1, dpv = v3 - v1; + float t1 = cross2d(dpu, dpv, su, sv) / denom; + float t2 = cross2d(dpu, dpv, ru, rv) / denom; + return 0.f <= t1 && t1 <= 1.0f && 0.f <= t2 && t2 <= 1.f; +}; + +class TriangleCursor : public TriangleSelector::SinglePointCursor +{ +public: + TriangleCursor() = delete; + explicit TriangleCursor(const Vec3f& center_, + const Vec3f& source_, + float radius_world, + const Transform3d& trafo_, + const TriangleSelector::ClippingPlane& clipping_plane_, + const std::array& vertices) + : TriangleSelector::SinglePointCursor(center_, source_, radius_world, trafo_, clipping_plane_) + , vertices_(vertices) + {} + ~TriangleCursor() override = default; + + static std::unique_ptr build_cursor(const TriangleSelector& source_selector, const TriangleSelector::Triangle& tri) + { + const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v; + const Vec3f& pv1 = source_selector.m_vertices[tri.verts_idxs[1]].v; + const Vec3f& pv2 = source_selector.m_vertices[tri.verts_idxs[2]].v; + + // Calculate the centroid of the triangle + const Vec3f center = (pv0 + pv1 + pv2) / 3.f; + + // Calculate the norm of the plane + const Vec3f& norm = source_selector.m_face_normals[tri.source_triangle]; + + // Calculate the min distance from the centroid to every edges + const float radius = std::max(std::min(std::min(point_to_line_dist(center, pv0, pv1), point_to_line_dist(center, pv0, pv2)), + point_to_line_dist(center, pv1, pv2)), 0.1f); + + return std::make_unique(center, center + norm, radius, Transform3d::Identity(), TriangleSelector::ClippingPlane(), + std::array{pv0, pv1, pv2}); + } + + bool is_mesh_point_inside(const Vec3f& point) const override + { + return is_point_inside_triangle(point, vertices_[0], vertices_[1], vertices_[2]); + } + + bool is_edge_inside_cursor(const TriangleSelector::Triangle& tr, const std::vector& vertices) const override + { + std::array pts_proj; // Projected point onto the plane + std::array pts_dist; // Distance to the plane, positive means above, negative means below the plane + for (int i = 0; i < 3; ++i) { + Vec3f p = vertices[tr.verts_idxs[i]].v; + if (!this->uniform_scaling) + p = this->trafo * p; + + const Vec3f diff = p - center; + pts_dist[i] = diff.dot(dir); + pts_proj[i] = p - pts_dist[i] * dir; + } + + for (int side = 0; side < 3; ++side) { + const int idx_a = side; + const int idx_b = side < 2 ? side + 1 : 0; + + // If both ends at the same side and farther than tolerance, skip + const float dist_a = pts_dist[idx_a]; + const float dist_b = pts_dist[idx_b]; + if ((dist_a > tolerance_ && dist_b > tolerance_) || (dist_a < -tolerance_ && dist_b < -tolerance_)) { + continue; + } + + // Find the projected line segment which has distance to the plane within the tolerance + Vec3f pt_a = pts_proj[idx_a]; + Vec3f pt_b = pts_proj[idx_b]; + if (std::abs(dist_a) > tolerance_) { + pt_a = (tolerance_ - dist_b) / (dist_a - dist_b) * (pts_proj[idx_a] - pts_proj[idx_b]); + } + if (std::abs(dist_b) > tolerance_) { + pt_b = (tolerance_ - dist_a) / (dist_b - dist_a) * (pts_proj[idx_b] - pts_proj[idx_a]); + } + + // If any projected end is inside the triangle, then is in + if (is_point_inside_triangle(pt_a, vertices_[0], vertices_[1], vertices_[2]) || + is_point_inside_triangle(pt_b, vertices_[0], vertices_[1], vertices_[2])) { + return true; + } + + // Otherwise see if the segment (pt_a, pt_b) intersects the triangle + { + const Vec3f uvw_a = barycentric(pt_a, vertices_[0], vertices_[1], vertices_[2]); + const Vec3f uvw_b = barycentric(pt_b, vertices_[0], vertices_[1], vertices_[2]); + auto proj = [&](const Vec3f& p) -> std::pair { return {p(0), p(1)}; }; + const Vec3f uvw_0 = {1.f,0.f,0.f}; + const Vec3f uvw_1 = {0.f,1.f,0.f}; + const Vec3f uvw_2 = {0.f,0.f,1.f}; + + if (segments_intersect_proj(uvw_a, uvw_b, uvw_0, uvw_1, proj)|| + segments_intersect_proj(uvw_a, uvw_b, uvw_0, uvw_2, proj)|| + segments_intersect_proj(uvw_a, uvw_b, uvw_1, uvw_2, proj)) { + return true; + } + } + } + return false; + } + + bool is_facet_visible(int facet_idx, const std::vector& face_normals) const override + { + return TriangleSelector::Cursor::is_facet_visible(*this, facet_idx, face_normals); + } + +private: + const std::array vertices_; + const float tolerance_ = EPSILON; + const float tolerance_sqr_ = tolerance_ * tolerance_; + + static float point_to_line_dist(const Vec3f& p, const Vec3f& a, const Vec3f& b) + { + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(a, b); + return line.distance(p); + } +}; + +// Remap painting data from source mesh to target mesh using spatial mapping. +TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( + const indexed_triangle_set& source_its, + const TriangleSplittingData& source_painting, + const indexed_triangle_set& target_its) +{ + TriangleSelector::TriangleSplittingData result; + if (source_painting.bitstream.empty()) + return result; + + // 1. Deserialize source painting + TriangleMesh source_mesh(source_its); + TriangleSelector source_selector(source_mesh); + source_selector.deserialize(source_painting, false); + + // 2. Extract painted geometry + std::vector> painted_triangles; + painted_triangles.reserve(source_selector.m_triangles.size()); + for (const Triangle& tr : source_selector.m_triangles) { + if (tr.valid() && !tr.is_split() && tr.get_state() != EnforcerBlockerType::NONE) { + painted_triangles.push_back(std::ref(tr)); + } + } + + if (painted_triangles.empty()) + return result; + + // 3. Build AABB tree of target mesh so we could find nearest face quickly + AABBTreeIndirect::Tree3f target_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(target_its.vertices, target_its.indices); + + // Helper: check overlap between a paint triangle and a target triangle. + // Uses 3D barycentric point-in-triangle tests and dominant-axis 2D projection + // for edge-edge intersection to handle all triangle orientations correctly. + auto check_overlap = [&](const Vec3f& pa, const Vec3f& pb, const Vec3f& pc, + const Vec3f& ta, const Vec3f& tb, const Vec3f& tc) -> bool { + // Check if any target vertex is inside the paint triangle + if (is_point_inside_triangle(ta, pa, pb, pc)) return true; + if (is_point_inside_triangle(tb, pa, pb, pc)) return true; + if (is_point_inside_triangle(tc, pa, pb, pc)) return true; + + // Check if any paint vertex is inside the target triangle + if (is_point_inside_triangle(pa, ta, tb, tc)) return true; + if (is_point_inside_triangle(pb, ta, tb, tc)) return true; + if (is_point_inside_triangle(pc, ta, tb, tc)) return true; + + // Check edge-edge intersections using dominant-axis 2D projection. + // Project onto the plane (XY, XZ, or YZ) where the triangles have the + // most area, avoiding degenerate projections for vertical/angled surfaces. + Vec3f n1 = (pb - pa).cross(pc - pa); + Vec3f n2 = (tb - ta).cross(tc - ta); + Vec3f n_abs = (n1.cwiseAbs() + n2.cwiseAbs()); + int axis = (n_abs.x() >= n_abs.y() && n_abs.x() >= n_abs.z()) ? 0 + : (n_abs.y() >= n_abs.z()) ? 1 : 2; + int u_axis = (axis + 1) % 3; + int v_axis = (axis + 2) % 3; + + auto proj = [&](const Vec3f& p) -> std::pair { + return { p(u_axis), p(v_axis) }; + }; + + if (segments_intersect_proj(pa, pb, ta, tb, proj)) return true; + if (segments_intersect_proj(pa, pb, tb, tc, proj)) return true; + if (segments_intersect_proj(pa, pb, tc, ta, proj)) return true; + if (segments_intersect_proj(pb, pc, ta, tb, proj)) return true; + if (segments_intersect_proj(pb, pc, tb, tc, proj)) return true; + if (segments_intersect_proj(pb, pc, tc, ta, proj)) return true; + if (segments_intersect_proj(pc, pa, ta, tb, proj)) return true; + if (segments_intersect_proj(pc, pa, tb, tc, proj)) return true; + if (segments_intersect_proj(pc, pa, tc, ta, proj)) return true; + + return false; + }; + + // 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it + TriangleMesh target_mesh(target_its); + TriangleSelector target_selector(target_mesh); + const auto facet_angle_limit = cos(Geometry::deg2rad(5)); + auto check_normal = [&source_selector, &target_selector, facet_angle_limit](int src_idx, int dst_idx) -> bool { + const Vec3f& norm_a = source_selector.m_face_normals[src_idx]; + const Vec3f& norm_b = target_selector.m_face_normals[dst_idx]; + const float a = norm_a.dot(norm_b); + + return std::clamp(a, 0.f, 1.f) >= facet_angle_limit; + }; + for (auto tri_ref : painted_triangles) { + const Triangle& tri = tri_ref.get(); + const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v; + const Vec3f& pv1 = source_selector.m_vertices[tri.verts_idxs[1]].v; + const Vec3f& pv2 = source_selector.m_vertices[tri.verts_idxs[2]].v; + + // Find ALL target faces whose bounding boxes overlap with the paint + // triangle's bounding box, not just the nearest one. + Eigen::AlignedBox3f pt_bbox; + pt_bbox.extend(pv0); + pt_bbox.extend(pv1); + pt_bbox.extend(pv2); + + AABBTreeIndirect::traverse(target_tree, AABBTreeIndirect::intersecting(pt_bbox), [&](const AABBTreeIndirect::Tree3f::Node& node) -> bool { + size_t face_idx = node.idx; + if (face_idx >= target_its.indices.size()) + return true; + + const Vec3i32& face = target_its.indices[face_idx]; + const Vec3f& ta = target_its.vertices[face(0)]; + const Vec3f& tb = target_its.vertices[face(1)]; + const Vec3f& tc = target_its.vertices[face(2)]; + + if (check_normal(tri.source_triangle, face_idx) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) { + // Paint this face + target_selector.select_patch(face_idx, TriangleCursor::build_cursor(source_selector, tri), tri.get_state(), + Transform3d::Identity(), true); + } + return true; // continue traversal + }); + } + + return target_selector.serialize(); +} + } // namespace Slic3r diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 50bbdd4ed0..99ad19548e 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -372,6 +372,13 @@ public: // The operation may merge split triangles if they are being assigned the same color. void seed_fill_apply_on_triangles(EnforcerBlockerType new_state); + // Remap painting data from source mesh to target mesh using spatial mapping. + // Both meshes must be in the same coordinate space. + static TriangleSplittingData remap_painting( + const indexed_triangle_set& source_its, + const TriangleSplittingData& source_painting, + const indexed_triangle_set& target_its); + protected: // Triangle and info about how it's split. class Triangle { @@ -521,11 +528,10 @@ private: int m_free_triangles_head { -1 }; int m_free_vertices_head { -1 }; + + friend class TriangleCursor; }; - - - } // namespace Slic3r #endif // libslic3r_TriangleSelector_hpp_ From e451df27f792bf6455121a72c55c384dcd34ba32 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 11:05:48 +0800 Subject: [PATCH 004/127] Fix issue of pojection calculation --- src/libslic3r/TriangleSelector.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 6368955fce..ba6926d227 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -2299,10 +2299,10 @@ public: Vec3f pt_a = pts_proj[idx_a]; Vec3f pt_b = pts_proj[idx_b]; if (std::abs(dist_a) > tolerance_) { - pt_a = (tolerance_ - dist_b) / (dist_a - dist_b) * (pts_proj[idx_a] - pts_proj[idx_b]); + pt_a = (tolerance_ - dist_b) / (dist_a - dist_b) * (pts_proj[idx_a] - pts_proj[idx_b]) + pts_proj[idx_b]; } if (std::abs(dist_b) > tolerance_) { - pt_b = (tolerance_ - dist_a) / (dist_b - dist_a) * (pts_proj[idx_b] - pts_proj[idx_a]); + pt_b = (tolerance_ - dist_a) / (dist_b - dist_a) * (pts_proj[idx_b] - pts_proj[idx_a]) + pts_proj[idx_a]; } // If any projected end is inside the triangle, then is in @@ -2315,7 +2315,7 @@ public: { const Vec3f uvw_a = barycentric(pt_a, vertices_[0], vertices_[1], vertices_[2]); const Vec3f uvw_b = barycentric(pt_b, vertices_[0], vertices_[1], vertices_[2]); - auto proj = [&](const Vec3f& p) -> std::pair { return {p(0), p(1)}; }; + auto proj = [](const Vec3f& p) -> std::pair { return {p(0), p(1)}; }; const Vec3f uvw_0 = {1.f,0.f,0.f}; const Vec3f uvw_1 = {0.f,1.f,0.f}; const Vec3f uvw_2 = {0.f,0.f,1.f}; From 4b489339c623e8d66a1154686aba000147066a37 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 11:59:20 +0800 Subject: [PATCH 005/127] Check normal before expanding the painting to neighboring faces --- src/libslic3r/TriangleSelector.cpp | 33 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index ba6926d227..a38220e2a5 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -171,7 +171,7 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si } // Real-time collision detection, Ericson, Chapter 3.4 -inline Vec3f barycentric(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +static Vec3f barycentric(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) { std::array v = {p2 - p1, p3 - p1, pt - p1}; float d00 = v[0].dot(v[0]); @@ -186,7 +186,7 @@ inline Vec3f barycentric(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, cons return barycentric_cords; } -inline bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) +static bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) { Vec3f barycentric_cords = barycentric(pt, p1, p2, p3); return std::all_of(begin(barycentric_cords), end(barycentric_cords), [](float cord) { return 0.f <= cord && cord <= 1.0; }); @@ -2211,8 +2211,7 @@ std::vector TriangleSelector::extract_used_facet_states(con return out; } -inline bool segments_intersect_proj( - const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4, const std::function(const Vec3f&)>& proj) +static bool segments_intersect_proj(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4, const std::function(const Vec3f&)>& proj) { auto cross2d = [](float ax, float ay, float bx, float by) -> float { return ax * by - ay * bx; }; auto [u1, v1] = proj(p1); @@ -2332,13 +2331,22 @@ public: bool is_facet_visible(int facet_idx, const std::vector& face_normals) const override { - return TriangleSelector::Cursor::is_facet_visible(*this, facet_idx, face_normals); + const Vec3f& n = face_normals[facet_idx]; + + return check_normal(n, this->dir); + } + + static bool check_normal(const Vec3f& facet_norm, const Vec3f& camera_dir) + { + const float a = -(facet_norm.dot(camera_dir)); + return std::clamp(a, 0.f, 1.f) >= facet_angle_limit; } private: const std::array vertices_; const float tolerance_ = EPSILON; const float tolerance_sqr_ = tolerance_ * tolerance_; + static const double facet_angle_limit; static float point_to_line_dist(const Vec3f& p, const Vec3f& a, const Vec3f& b) { @@ -2346,6 +2354,8 @@ private: return line.distance(p); } }; +const double TriangleCursor::facet_angle_limit = cos(Geometry::deg2rad(5)); + // Remap painting data from source mesh to target mesh using spatial mapping. TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( @@ -2423,14 +2433,6 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( // 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it TriangleMesh target_mesh(target_its); TriangleSelector target_selector(target_mesh); - const auto facet_angle_limit = cos(Geometry::deg2rad(5)); - auto check_normal = [&source_selector, &target_selector, facet_angle_limit](int src_idx, int dst_idx) -> bool { - const Vec3f& norm_a = source_selector.m_face_normals[src_idx]; - const Vec3f& norm_b = target_selector.m_face_normals[dst_idx]; - const float a = norm_a.dot(norm_b); - - return std::clamp(a, 0.f, 1.f) >= facet_angle_limit; - }; for (auto tri_ref : painted_triangles) { const Triangle& tri = tri_ref.get(); const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v; @@ -2449,12 +2451,15 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( if (face_idx >= target_its.indices.size()) return true; + const Vec3f& norm_a = source_selector.m_face_normals[tri.source_triangle]; + const Vec3f& norm_b = target_selector.m_face_normals[face_idx]; + const Vec3i32& face = target_its.indices[face_idx]; const Vec3f& ta = target_its.vertices[face(0)]; const Vec3f& tb = target_its.vertices[face(1)]; const Vec3f& tc = target_its.vertices[face(2)]; - if (check_normal(tri.source_triangle, face_idx) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) { + if (TriangleCursor::check_normal(norm_b, -norm_a) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) { // Paint this face target_selector.select_patch(face_idx, TriangleCursor::build_cursor(source_selector, tri), tri.get_state(), Transform3d::Identity(), true); From 01e0013b1656c4e622c4d9d5090868b751ea5da2 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 17:08:53 +0800 Subject: [PATCH 006/127] Don't remap paint unless it's the final cut --- src/libslic3r/CutUtils.cpp | 47 ++++++++++++++-------------- src/libslic3r/CutUtils.hpp | 2 +- src/libslic3r/Model.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 3 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 7979dc4095..b69c4cf4ee 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -14,9 +14,9 @@ namespace Slic3r { using namespace Geometry; -// Saved painting data for remapping after mesh cutting. +// Saved painting data for remapping after mesh change. struct SavedPainting { - indexed_triangle_set its; // Original mesh transformed to cut space + indexed_triangle_set its; // Original mesh TriangleSelector::TriangleSplittingData supported; TriangleSelector::TriangleSplittingData seam; TriangleSelector::TriangleSplittingData mmu; @@ -24,21 +24,24 @@ struct SavedPainting { }; // Remap painting data from saved source to a cut result mesh, and set on a volume. -static void remap_and_set_painting(ModelVolume* vol, const indexed_triangle_set& cut_its, - const SavedPainting& saved) +static void remap_and_set_painting(ModelVolume* vol, const SavedPainting* saved) { + if (!saved) { + return; + } + auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data, FacetsAnnotation& target_facets) { if (src_data.bitstream.empty()) return; - auto result = TriangleSelector::remap_painting(saved.its, src_data, cut_its); + auto result = TriangleSelector::remap_painting(saved->its, src_data, vol->mesh().its); if (!result.bitstream.empty()) target_facets.set_data(result); }; - remap_one(saved.supported, vol->supported_facets); - remap_one(saved.seam, vol->seam_facets); - remap_one(saved.mmu, vol->mmu_segmentation_facets); - remap_one(saved.fuzzy, vol->fuzzy_skin_facets); + remap_one(saved->supported, vol->supported_facets); + remap_one(saved->seam, vol->seam_facets); + remap_one(saved->mmu, vol->mmu_segmentation_facets); + remap_one(saved->fuzzy, vol->fuzzy_skin_facets); } static void apply_tolerance(ModelVolume* vol) @@ -217,28 +220,26 @@ static void process_solid_part_cut(ModelVolume* volume, const Transform3d& insta // Add required cut parts to the objects if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { - add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); - if (saved_painting && !upper_mesh.empty()) - remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting); + if (!upper_mesh.empty()) { + add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); + remap_and_set_painting(upper->volumes.back(), saved_painting); + } if (!lower_mesh.empty()) { add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); - if (saved_painting) - remap_and_set_painting(upper->volumes.back(), lower_mesh.its, *saved_painting); upper->volumes.back()->cut_info.is_from_upper = false; + remap_and_set_painting(upper->volumes.back(), saved_painting); } return; } - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper_mesh.empty()) { add_cut_volume(upper_mesh, upper, volume, cut_matrix); - if (saved_painting && !upper_mesh.empty()) - remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting); + remap_and_set_painting(upper->volumes.back(), saved_painting); } if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { add_cut_volume(lower_mesh, lower, volume, cut_matrix); - if (saved_painting) - remap_and_set_painting(lower->volumes.back(), lower_mesh.its, *saved_painting); + remap_and_set_painting(lower->volumes.back(), saved_painting); } } @@ -363,21 +364,19 @@ const ModelObjectPtrs& Cut::perform_with_plane() // Save painting data before reset_extra_facets() discards it. // Only for model parts that will be cut (not modifiers/connectors). std::optional saved_painting; - if (volume->is_model_part() && !volume->mesh().empty()) { - SavedPainting sp; + if (m_attributes.has(ModelObjectCutAttribute::KeepPaint) && volume->is_any_painted() && volume->is_model_part() && !volume->mesh().empty()) { // Get mesh in cut space (same transform as process_volume_cut applies) TriangleMesh mesh(volume->mesh()); const auto volume_matrix = volume->get_matrix(); mesh.transform(inverse_cut_matrix * instance_matrix * volume_matrix, true); mesh.transform(m_cut_matrix); + SavedPainting sp; sp.its = std::move(mesh.its); sp.supported = volume->supported_facets.get_data(); sp.seam = volume->seam_facets.get_data(); sp.mmu = volume->mmu_segmentation_facets.get_data(); sp.fuzzy = volume->fuzzy_skin_facets.get_data(); - if (!sp.supported.bitstream.empty() || !sp.seam.bitstream.empty() || - !sp.mmu.bitstream.empty() || !sp.fuzzy.bitstream.empty()) - saved_painting = std::move(sp); + saved_painting = std::move(sp); } volume->reset_extra_facets(); diff --git a/src/libslic3r/CutUtils.hpp b/src/libslic3r/CutUtils.hpp index 2c477a3e2b..f39007c8a9 100644 --- a/src/libslic3r/CutUtils.hpp +++ b/src/libslic3r/CutUtils.hpp @@ -11,7 +11,7 @@ namespace Slic3r { using ModelObjectPtrs = std::vector; -enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo }; +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo, KeepPaint }; using ModelObjectCutAttributes = enum_bitmask; ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 302bf47935..0de76dbef4 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1005,6 +1005,7 @@ public: bool is_seam_painted() const { return !this->seam_facets.empty(); } bool is_mm_painted() const { return !this->mmu_segmentation_facets.empty(); } bool is_fuzzy_skin_painted() const { return !this->fuzzy_skin_facets.empty(); } + bool is_any_painted() const { return is_fdm_support_painted() || is_seam_painted() || is_mm_painted() || is_fuzzy_skin_painted(); } // Orca: Implement prusa's filament shrink compensation approach // Returns 0-based indices of extruders painted by multi-material painting gizmo. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 2483f7bd1b..59c14ef205 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3329,7 +3329,8 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) | - only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo); + only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo) | + ModelObjectCutAttribute::KeepPaint; // update cut_id for the cut object in respect to the attributes update_object_cut_id(cut_mo->cut_id, attributes, dowels_count); From 368563e14ef26bae0bc9463b73482fae1cc57781 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 17:55:38 +0800 Subject: [PATCH 007/127] Fix part offset --- src/libslic3r/CutUtils.cpp | 2 +- src/libslic3r/TriangleSelector.cpp | 18 ++++++++++-------- src/libslic3r/TriangleSelector.hpp | 5 +++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index b69c4cf4ee..16f0a19816 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -34,7 +34,7 @@ static void remap_and_set_painting(ModelVolume* vol, const SavedPainting* saved) FacetsAnnotation& target_facets) { if (src_data.bitstream.empty()) return; - auto result = TriangleSelector::remap_painting(saved->its, src_data, vol->mesh().its); + auto result = TriangleSelector::remap_painting(saved->its, src_data, vol->mesh().its, translation_transform(vol->mesh().get_init_shift())); if (!result.bitstream.empty()) target_facets.set_data(result); }; diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index a38220e2a5..d4821df7cd 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -2361,7 +2361,8 @@ const double TriangleCursor::facet_angle_limit = cos(Geometry::deg2rad(5)); TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( const indexed_triangle_set& source_its, const TriangleSplittingData& source_painting, - const indexed_triangle_set& target_its) + const indexed_triangle_set& target_its, + const Transform3d& target_transform) { TriangleSelector::TriangleSplittingData result; if (source_painting.bitstream.empty()) @@ -2385,7 +2386,9 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( return result; // 3. Build AABB tree of target mesh so we could find nearest face quickly - AABBTreeIndirect::Tree3f target_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(target_its.vertices, target_its.indices); + TriangleMesh target_mesh(target_its); + target_mesh.transform(target_transform); + AABBTreeIndirect::Tree3f target_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(target_mesh.its.vertices, target_mesh.its.indices); // Helper: check overlap between a paint triangle and a target triangle. // Uses 3D barycentric point-in-triangle tests and dominant-axis 2D projection @@ -2431,7 +2434,6 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( }; // 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it - TriangleMesh target_mesh(target_its); TriangleSelector target_selector(target_mesh); for (auto tri_ref : painted_triangles) { const Triangle& tri = tri_ref.get(); @@ -2448,16 +2450,16 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( AABBTreeIndirect::traverse(target_tree, AABBTreeIndirect::intersecting(pt_bbox), [&](const AABBTreeIndirect::Tree3f::Node& node) -> bool { size_t face_idx = node.idx; - if (face_idx >= target_its.indices.size()) + if (face_idx >= target_mesh.its.indices.size()) return true; const Vec3f& norm_a = source_selector.m_face_normals[tri.source_triangle]; const Vec3f& norm_b = target_selector.m_face_normals[face_idx]; - const Vec3i32& face = target_its.indices[face_idx]; - const Vec3f& ta = target_its.vertices[face(0)]; - const Vec3f& tb = target_its.vertices[face(1)]; - const Vec3f& tc = target_its.vertices[face(2)]; + const Vec3i32& face = target_mesh.its.indices[face_idx]; + const Vec3f& ta = target_mesh.its.vertices[face(0)]; + const Vec3f& tb = target_mesh.its.vertices[face(1)]; + const Vec3f& tc = target_mesh.its.vertices[face(2)]; if (TriangleCursor::check_normal(norm_b, -norm_a) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) { // Paint this face diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 99ad19548e..8f02c7d717 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -373,11 +373,12 @@ public: void seed_fill_apply_on_triangles(EnforcerBlockerType new_state); // Remap painting data from source mesh to target mesh using spatial mapping. - // Both meshes must be in the same coordinate space. + // `target_transform` should transform the target mesh into source's coordinate space. static TriangleSplittingData remap_painting( const indexed_triangle_set& source_its, const TriangleSplittingData& source_painting, - const indexed_triangle_set& target_its); + const indexed_triangle_set& target_its, + const Transform3d& target_transform); protected: // Triangle and info about how it's split. From 5978e96ff5a8b643afc85e899bf53a788f646726 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 18:39:50 +0800 Subject: [PATCH 008/127] Add option to enable/disable paint keep --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 2 +- src/slic3r/GUI/Preferences.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 59c14ef205..bfc757589c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3330,7 +3330,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) | only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo) | - ModelObjectCutAttribute::KeepPaint; + only_if(wxGetApp().app_config->get_bool("keep_painting"),ModelObjectCutAttribute::KeepPaint); // update cut_id for the cut object in respect to the attributes update_object_cut_id(cut_mo->cut_id, attributes, dowels_count); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index c5d377b67b..fc27d27e31 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -956,7 +956,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: " << (sync ? "true" : "false"); } - #ifdef __WXMSW__ +#ifdef __WXMSW__ if (param == "associate_3mf") { bool pbool = app_config->get("associate_3mf") == "true" ? true : false; if (pbool) { @@ -1776,6 +1776,9 @@ void PreferencesDialog::create_items() auto item_ams_blacklist = create_item_checkbox(_L("Skip AMS blacklist check"), "", "skip_ams_blacklist_check"); g_sizer->Add(item_ams_blacklist); + auto item_keep_painting = create_item_checkbox(_L("(Experimental) Keep painted feature after mesh change"), _L("Attempt to keep painted features (color/seam/support/fuzzy etc.) after changing the object mesh (such as cut/reload from disk/simplify/fix etc.)\nHighly experimental! Slow and may create artifact."), "keep_painting"); + g_sizer->Add(item_keep_painting); + g_sizer->Add(create_item_title(_L("Storage")), 1, wxEXPAND); auto item_allow_abnormal_storage = create_item_checkbox(_L("Allow Abnormal Storage"), _L("This allows the use of Storage that is marked as abnormal by the Printer.\nUse at your own risk, can cause issues!"), "allow_abnormal_storage"); g_sizer->Add(item_allow_abnormal_storage); From be141d32c18a16e7aaa5b15f89af06f62a97d721 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 5 May 2026 21:43:29 +0800 Subject: [PATCH 009/127] Speed up calculation by caching barycentric independent variables --- src/libslic3r/TriangleSelector.cpp | 124 +++++++++++++++++++---------- 1 file changed, 83 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index d4821df7cd..e4d1a4521c 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -170,25 +170,69 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si this->special_side_idx = char(special_side_idx); } +// Pre-computed barycentric resolver // Real-time collision detection, Ericson, Chapter 3.4 -static Vec3f barycentric(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +// Cache inspired by Don Hatch at https://gamedev.stackexchange.com/questions/23743/whats-the-most-efficient-way-to-find-barycentric-coordinates/23745#comment390123_23745 +struct Barycentric { - std::array v = {p2 - p1, p3 - p1, pt - p1}; - float d00 = v[0].dot(v[0]); - float d01 = v[0].dot(v[1]); - float d11 = v[1].dot(v[1]); - float d20 = v[2].dot(v[0]); - float d21 = v[2].dot(v[1]); - float denom = d00 * d11 - d01 * d01; +public: + Barycentric(const Vec3f& a, const Vec3f& b, const Vec3f& c) + :a_(a) + { + // Pre-compute denominator + const Vec3f v0 = b - a; + const Vec3f v1 = c - a; + const float d00 = v0.dot(v0); + const float d01 = v0.dot(v1); + const float d11 = v1.dot(v1); + const float inv_denom_ = 1.0f / (d00 * d11 - d01 * d01); + + x1_ = (d11 * v0 - d01 * v1) * inv_denom_; + x2_ = (d00 * v1 - d01 * v0) * inv_denom_; + } - Vec3f barycentric_cords(1.f, (d11 * d20 - d01 * d21) / denom, (d00 * d21 - d01 * d20) / denom); - barycentric_cords.x() = barycentric_cords.x() - barycentric_cords.y() - barycentric_cords.z(); - return barycentric_cords; -} + Vec3f calc(const Vec3f& p) const + { + const Vec3f v2 = p - a_; + const float v = v2.dot(x1_); + const float w = v2.dot(x2_); + const float u = 1.f - v - w; + + return {u, v, w}; + } + + bool is_point_inside_triangle(const Vec3f& p) const + { + const Vec3f barycentric_cords = calc(p); + return std::all_of(begin(barycentric_cords), end(barycentric_cords), [](float cord) { return 0.f <= cord && cord <= 1.0; }); + } + + static Vec3f calc(const Vec3f& pt, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) + { + const std::array vec = {p2 - p1, p3 - p1, pt - p1}; + const float d00 = vec[0].dot(vec[0]); + const float d01 = vec[0].dot(vec[1]); + const float d11 = vec[1].dot(vec[1]); + const float d20 = vec[2].dot(vec[0]); + const float d21 = vec[2].dot(vec[1]); + const float denom = d00 * d11 - d01 * d01; + + const float v = (d11 * d20 - d01 * d21) / denom; + const float w = (d00 * d21 - d01 * d20) / denom; + const float u = 1.f - v - w; + + return {u, v, w}; + } + +private: + Vec3f a_; + Vec3f x1_; + Vec3f x2_; +}; static bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) { - Vec3f barycentric_cords = barycentric(pt, p1, p2, p3); + Vec3f barycentric_cords = Barycentric::calc(pt, p1, p2, p3); return std::all_of(begin(barycentric_cords), end(barycentric_cords), [](float cord) { return 0.f <= cord && cord <= 1.0; }); } @@ -2211,21 +2255,22 @@ std::vector TriangleSelector::extract_used_facet_states(con return out; } -static bool segments_intersect_proj(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4, const std::function(const Vec3f&)>& proj) +static bool segments_intersect_proj(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4, const std::pair& proj) { auto cross2d = [](float ax, float ay, float bx, float by) -> float { return ax * by - ay * bx; }; - auto [u1, v1] = proj(p1); - auto [u2, v2] = proj(p2); - auto [u3, v3] = proj(p3); - auto [u4, v4] = proj(p4); - float ru = u2 - u1, rv = v2 - v1; - float su = u4 - u3, sv = v4 - v3; - float denom = cross2d(ru, rv, su, sv); + const auto [u_axis, v_axis] = proj; + const auto u1 = p1(u_axis), v1 = p1(v_axis); + const auto u2 = p2(u_axis), v2 = p2(v_axis); + const auto u3 = p3(u_axis), v3 = p3(v_axis); + const auto u4 = p4(u_axis), v4 = p4(v_axis); + const float ru = u2 - u1, rv = v2 - v1; + const float su = u4 - u3, sv = v4 - v3; + const float denom = cross2d(ru, rv, su, sv); if (std::abs(denom) < 1e-10f) return false; - float dpu = u3 - u1, dpv = v3 - v1; - float t1 = cross2d(dpu, dpv, su, sv) / denom; - float t2 = cross2d(dpu, dpv, ru, rv) / denom; + const float dpu = u3 - u1, dpv = v3 - v1; + const float t1 = cross2d(dpu, dpv, su, sv) / denom; + const float t2 = cross2d(dpu, dpv, ru, rv) / denom; return 0.f <= t1 && t1 <= 1.0f && 0.f <= t2 && t2 <= 1.f; }; @@ -2240,7 +2285,7 @@ public: const TriangleSelector::ClippingPlane& clipping_plane_, const std::array& vertices) : TriangleSelector::SinglePointCursor(center_, source_, radius_world, trafo_, clipping_plane_) - , vertices_(vertices) + , barycentric_(vertices[0], vertices[1], vertices[2]) {} ~TriangleCursor() override = default; @@ -2266,7 +2311,7 @@ public: bool is_mesh_point_inside(const Vec3f& point) const override { - return is_point_inside_triangle(point, vertices_[0], vertices_[1], vertices_[2]); + return barycentric_.is_point_inside_triangle(point); } bool is_edge_inside_cursor(const TriangleSelector::Triangle& tr, const std::vector& vertices) const override @@ -2305,19 +2350,19 @@ public: } // If any projected end is inside the triangle, then is in - if (is_point_inside_triangle(pt_a, vertices_[0], vertices_[1], vertices_[2]) || - is_point_inside_triangle(pt_b, vertices_[0], vertices_[1], vertices_[2])) { + if (barycentric_.is_point_inside_triangle(pt_a) || + barycentric_.is_point_inside_triangle(pt_b)) { return true; } // Otherwise see if the segment (pt_a, pt_b) intersects the triangle { - const Vec3f uvw_a = barycentric(pt_a, vertices_[0], vertices_[1], vertices_[2]); - const Vec3f uvw_b = barycentric(pt_b, vertices_[0], vertices_[1], vertices_[2]); - auto proj = [](const Vec3f& p) -> std::pair { return {p(0), p(1)}; }; - const Vec3f uvw_0 = {1.f,0.f,0.f}; - const Vec3f uvw_1 = {0.f,1.f,0.f}; - const Vec3f uvw_2 = {0.f,0.f,1.f}; + const Vec3f uvw_a = barycentric_.calc(pt_a); + const Vec3f uvw_b = barycentric_.calc(pt_b); + const Vec3f uvw_0 {1.f,0.f,0.f}; + const Vec3f uvw_1 {0.f,1.f,0.f}; + const Vec3f uvw_2 {0.f,0.f,1.f}; + constexpr std::pair proj{0, 1}; if (segments_intersect_proj(uvw_a, uvw_b, uvw_0, uvw_1, proj)|| segments_intersect_proj(uvw_a, uvw_b, uvw_0, uvw_2, proj)|| @@ -2343,7 +2388,7 @@ public: } private: - const std::array vertices_; + const Barycentric barycentric_; const float tolerance_ = EPSILON; const float tolerance_sqr_ = tolerance_ * tolerance_; static const double facet_angle_limit; @@ -2413,12 +2458,9 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( Vec3f n_abs = (n1.cwiseAbs() + n2.cwiseAbs()); int axis = (n_abs.x() >= n_abs.y() && n_abs.x() >= n_abs.z()) ? 0 : (n_abs.y() >= n_abs.z()) ? 1 : 2; - int u_axis = (axis + 1) % 3; - int v_axis = (axis + 2) % 3; - - auto proj = [&](const Vec3f& p) -> std::pair { - return { p(u_axis), p(v_axis) }; - }; + const int u_axis = (axis + 1) % 3; + const int v_axis = (axis + 2) % 3; + const std::pair proj{u_axis, v_axis}; if (segments_intersect_proj(pa, pb, ta, tb, proj)) return true; if (segments_intersect_proj(pa, pb, tb, tc, proj)) return true; From 83e9f17aa817c28c03ea68db610aca59feebca44 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 7 May 2026 22:24:45 +0800 Subject: [PATCH 010/127] Fix issue that `Geometry::deg2rad()` do calculation in the same type as the parameter, which means if the parameter is `int` then you lose all the precision --- src/libslic3r/Geometry.hpp | 6 +++++- src/libslic3r/TriangleSelector.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 0ae7524fa0..e610a9ed4f 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -298,7 +298,11 @@ bool directions_perpendicular(double angle1, double angle2, double max_diff = 0) template bool contains(const std::vector &vector, const Point &point); template T rad2deg(T angle) { return T(180.0) * angle / T(PI); } double rad2deg_dir(double angle); -template constexpr T deg2rad(const T angle) { return T(PI) * angle / T(180.0); } +template constexpr T deg2rad(const T angle) +{ + static_assert(std::is_floating_point::value, "Why do you want to calculate angle in integer?"); + return T(PI) * angle / T(180.0); +} template T angle_to_0_2PI(T angle) { static const T TWO_PI = T(2) * T(PI); diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index e4d1a4521c..19f638a160 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -2399,7 +2399,7 @@ private: return line.distance(p); } }; -const double TriangleCursor::facet_angle_limit = cos(Geometry::deg2rad(5)); +const double TriangleCursor::facet_angle_limit = cos(Geometry::deg2rad(5.0)); // Remap painting data from source mesh to target mesh using spatial mapping. From fad680fcc160034f0aaa03d52e1a2366529a731e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 8 May 2026 21:23:38 +0800 Subject: [PATCH 011/127] Simplify mesh transform --- src/libslic3r/CutUtils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 16f0a19816..a2cd7583a5 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -368,8 +368,7 @@ const ModelObjectPtrs& Cut::perform_with_plane() // Get mesh in cut space (same transform as process_volume_cut applies) TriangleMesh mesh(volume->mesh()); const auto volume_matrix = volume->get_matrix(); - mesh.transform(inverse_cut_matrix * instance_matrix * volume_matrix, true); - mesh.transform(m_cut_matrix); + mesh.transform(instance_matrix * volume_matrix, true); SavedPainting sp; sp.its = std::move(mesh.its); sp.supported = volume->supported_facets.get_data(); From 2f160ad8bc397431d1146ecbec757130de2c90dd Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 8 May 2026 22:54:20 +0800 Subject: [PATCH 012/127] Rearrange code a little bit to make it more reusable --- src/libslic3r/CutUtils.cpp | 40 +++++++++--------------------- src/libslic3r/Model.hpp | 18 ++++++++++++++ src/libslic3r/TriangleSelector.hpp | 9 +++++++ 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index a2cd7583a5..8586b952f3 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -14,17 +14,8 @@ namespace Slic3r { using namespace Geometry; -// Saved painting data for remapping after mesh change. -struct SavedPainting { - indexed_triangle_set its; // Original mesh - TriangleSelector::TriangleSplittingData supported; - TriangleSelector::TriangleSplittingData seam; - TriangleSelector::TriangleSplittingData mmu; - TriangleSelector::TriangleSplittingData fuzzy; -}; - // Remap painting data from saved source to a cut result mesh, and set on a volume. -static void remap_and_set_painting(ModelVolume* vol, const SavedPainting* saved) +static void remap_and_set_painting(ModelVolume* vol, const std::optional& saved) { if (!saved) { return; @@ -34,7 +25,7 @@ static void remap_and_set_painting(ModelVolume* vol, const SavedPainting* saved) FacetsAnnotation& target_facets) { if (src_data.bitstream.empty()) return; - auto result = TriangleSelector::remap_painting(saved->its, src_data, vol->mesh().its, translation_transform(vol->mesh().get_init_shift())); + auto result = TriangleSelector::remap_painting(saved->mesh.its, src_data, vol->mesh().its, translation_transform(vol->mesh().get_init_shift())); if (!result.bitstream.empty()) target_facets.set_data(result); }; @@ -211,7 +202,7 @@ static void process_modifier_cut(ModelVolume* volume, const Transform3d& instanc static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, - const SavedPainting* saved_painting = nullptr) + const std::optional& saved_painting) { // Perform cut TriangleMesh upper_mesh, lower_mesh; @@ -362,20 +353,14 @@ const ModelObjectPtrs& Cut::perform_with_plane() for (ModelVolume* volume : mo->volumes) { // Save painting data before reset_extra_facets() discards it. - // Only for model parts that will be cut (not modifiers/connectors). - std::optional saved_painting; - if (m_attributes.has(ModelObjectCutAttribute::KeepPaint) && volume->is_any_painted() && volume->is_model_part() && !volume->mesh().empty()) { - // Get mesh in cut space (same transform as process_volume_cut applies) - TriangleMesh mesh(volume->mesh()); - const auto volume_matrix = volume->get_matrix(); - mesh.transform(instance_matrix * volume_matrix, true); - SavedPainting sp; - sp.its = std::move(mesh.its); - sp.supported = volume->supported_facets.get_data(); - sp.seam = volume->seam_facets.get_data(); - sp.mmu = volume->mmu_segmentation_facets.get_data(); - sp.fuzzy = volume->fuzzy_skin_facets.get_data(); - saved_painting = std::move(sp); + std::optional saved_painting; + if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) { + saved_painting = volume->save_painting(); + if (saved_painting) { + // Transform mesh to cut space (same transform as process_volume_cut applies) + const auto volume_matrix = volume->get_matrix(); + saved_painting->mesh.transform(instance_matrix * volume_matrix, true); + } } volume->reset_extra_facets(); @@ -387,8 +372,7 @@ const ModelObjectPtrs& Cut::perform_with_plane() process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels); } else if (!volume->mesh().empty()) - process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, - saved_painting ? &*saved_painting : nullptr); + process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, saved_painting); } // Post-process cut parts diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0de76dbef4..ccc0760097 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -878,6 +878,24 @@ public: // List of mesh facets painted for fuzzy skin. FacetsAnnotation fuzzy_skin_facets; + // Save painting data before reset_extra_facets() discards it. + // Used for replacing mesh without losing painting data. + // Only for model parts (not modifiers/connectors). + std::optional save_painting() const + { + if (is_any_painted() && is_model_part() && !mesh().empty()) { + TriangleSelector::SavedPainting sp; + sp.mesh = mesh(); + sp.supported = supported_facets.get_data(); + sp.seam = seam_facets.get_data(); + sp.mmu = mmu_segmentation_facets.get_data(); + sp.fuzzy = fuzzy_skin_facets.get_data(); + return sp; + } + + return {}; + } + // BBS: quick access for volume extruders, 1 based mutable std::vector mmuseg_extruders; mutable Timestamp mmuseg_ts; diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 8f02c7d717..412c9fb9b1 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -372,6 +372,15 @@ public: // The operation may merge split triangles if they are being assigned the same color. void seed_fill_apply_on_triangles(EnforcerBlockerType new_state); + // Saved painting data for remapping after mesh change. + struct SavedPainting { + TriangleMesh mesh; // Original mesh + TriangleSplittingData supported; + TriangleSplittingData seam; + TriangleSplittingData mmu; + TriangleSplittingData fuzzy; + }; + // Remap painting data from source mesh to target mesh using spatial mapping. // `target_transform` should transform the target mesh into source's coordinate space. static TriangleSplittingData remap_painting( From 4490dccade7deb179a9b763dc748209fb450be72 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 10:12:36 +0800 Subject: [PATCH 013/127] Fix issue that support/seam/fuzzy skin painting not kept after split --- src/libslic3r/Model.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ef5ef6dbe6..bcdf1e54d3 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2078,10 +2078,16 @@ void ModelObject::split(ModelObjectPtrs* new_objects) ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh)); if (is_multi_volume_object) { - // BBS: volume geometry not changed, so we can keep the color paint facets - if (new_vol->mmu_segmentation_facets.timestamp() == volume->mmu_segmentation_facets.timestamp()) - new_vol->mmu_segmentation_facets.reset(); // BBS: let next assign take effect - new_vol->mmu_segmentation_facets.assign(volume->mmu_segmentation_facets); + // BBS: volume geometry not changed, so we can keep the paint facets +#define COPY_FACETS(f) \ + if (new_vol->f.timestamp() == volume->f.timestamp()) \ + new_vol->f.reset(); /* BBS: let next assign take effect */ \ + new_vol->f.assign(volume->f) + + COPY_FACETS(supported_facets); + COPY_FACETS(seam_facets); + COPY_FACETS(mmu_segmentation_facets); + COPY_FACETS(fuzzy_skin_facets); } // BBS: clear volume's config, as we already set them into object From bfde91685e420d1f29801c39be29bbbabe2eb7cd Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 16:16:06 +0800 Subject: [PATCH 014/127] Rearrange code a little bit to make it more reusable --- src/libslic3r/CutUtils.cpp | 29 ++++------------------------- src/libslic3r/Model.cpp | 35 +++++++++++++++++++++++++++++++++++ src/libslic3r/Model.hpp | 18 ++++-------------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 8586b952f3..7fc21bb3b4 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -14,27 +14,6 @@ namespace Slic3r { using namespace Geometry; -// Remap painting data from saved source to a cut result mesh, and set on a volume. -static void remap_and_set_painting(ModelVolume* vol, const std::optional& saved) -{ - if (!saved) { - return; - } - - auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data, - FacetsAnnotation& target_facets) { - if (src_data.bitstream.empty()) - return; - auto result = TriangleSelector::remap_painting(saved->mesh.its, src_data, vol->mesh().its, translation_transform(vol->mesh().get_init_shift())); - if (!result.bitstream.empty()) - target_facets.set_data(result); - }; - remap_one(saved->supported, vol->supported_facets); - remap_one(saved->seam, vol->seam_facets); - remap_one(saved->mmu, vol->mmu_segmentation_facets); - remap_one(saved->fuzzy, vol->fuzzy_skin_facets); -} - static void apply_tolerance(ModelVolume* vol) { ModelVolume::CutInfo& cut_info = vol->cut_info; @@ -213,24 +192,24 @@ static void process_solid_part_cut(ModelVolume* volume, const Transform3d& insta if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { if (!upper_mesh.empty()) { add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); - remap_and_set_painting(upper->volumes.back(), saved_painting); + upper->volumes.back()->restore_painting(saved_painting); } if (!lower_mesh.empty()) { add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); upper->volumes.back()->cut_info.is_from_upper = false; - remap_and_set_painting(upper->volumes.back(), saved_painting); + upper->volumes.back()->restore_painting(saved_painting); } return; } if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper_mesh.empty()) { add_cut_volume(upper_mesh, upper, volume, cut_matrix); - remap_and_set_painting(upper->volumes.back(), saved_painting); + upper->volumes.back()->restore_painting(saved_painting); } if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { add_cut_volume(lower_mesh, lower, volume, cut_matrix); - remap_and_set_painting(lower->volumes.back(), saved_painting); + lower->volumes.back()->restore_painting(saved_painting); } } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index bcdf1e54d3..57a114479b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1980,6 +1980,41 @@ void ModelVolume::reset_extra_facets() this->fuzzy_skin_facets.reset(); } +std::optional ModelVolume::save_painting() const +{ + if (is_any_painted() && is_model_part() && !mesh().empty()) { + TriangleSelector::SavedPainting sp; + sp.mesh = mesh(); + sp.supported = supported_facets.get_data(); + sp.seam = seam_facets.get_data(); + sp.mmu = mmu_segmentation_facets.get_data(); + sp.fuzzy = fuzzy_skin_facets.get_data(); + return sp; + } + + return {}; +} + +void ModelVolume::restore_painting(const std::optional& saved) +{ + if (!saved) { + return; + } + + auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data, + FacetsAnnotation& target_facets) { + if (src_data.bitstream.empty()) + return; + auto result = TriangleSelector::remap_painting(saved->mesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift())); + if (!result.bitstream.empty()) + target_facets.set_data(result); + }; + remap_one(saved->supported, supported_facets); + remap_one(saved->seam, seam_facets); + remap_one(saved->mmu, mmu_segmentation_facets); + remap_one(saved->fuzzy, fuzzy_skin_facets); +} + static void invalidate_translations(ModelObject* object, const ModelInstance* src_instance) { if (!object->origin_translation.isApprox(Vec3d::Zero()) && src_instance->get_offset().isApprox(Vec3d::Zero())) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ccc0760097..5bf345607d 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -881,20 +881,10 @@ public: // Save painting data before reset_extra_facets() discards it. // Used for replacing mesh without losing painting data. // Only for model parts (not modifiers/connectors). - std::optional save_painting() const - { - if (is_any_painted() && is_model_part() && !mesh().empty()) { - TriangleSelector::SavedPainting sp; - sp.mesh = mesh(); - sp.supported = supported_facets.get_data(); - sp.seam = seam_facets.get_data(); - sp.mmu = mmu_segmentation_facets.get_data(); - sp.fuzzy = fuzzy_skin_facets.get_data(); - return sp; - } - - return {}; - } + std::optional save_painting() const; + + // Remap painting data from previous saved source to this mesh + void restore_painting(const std::optional& saved); // BBS: quick access for volume extruders, 1 based mutable std::vector mmuseg_extruders; From c2d33bea08d1d6e51451d51248382b0a98294257 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 16:18:49 +0800 Subject: [PATCH 015/127] Remap paint after split to objects --- src/OrcaSlicer.cpp | 2 +- src/libslic3r/Model.cpp | 10 +++++++++- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index ba52f6787b..b258e096d4 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -4450,7 +4450,7 @@ int CLI::run(int argc, char **argv) size_t num_objects = model.objects.size(); for (size_t i = 0; i < num_objects; ++ i) { ModelObjectPtrs new_objects; - model.objects.front()->split(&new_objects); + model.objects.front()->split(&new_objects, false); // TODO: add cli option to enable this? model.delete_object(size_t(0)); } } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 57a114479b..09751cd7df 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2028,13 +2028,14 @@ static void invalidate_translations(ModelObject* object, const ModelInstance* sr } } -void ModelObject::split(ModelObjectPtrs* new_objects) +void ModelObject::split(ModelObjectPtrs* new_objects, const bool remap_paint) { std::vector all_meshes; std::vector all_transfos; std::vector> volume_mesh_counts; all_meshes.reserve(this->volumes.size() * 5); bool is_multi_volume_object = (this->volumes.size() > 1); + std::optional saved_painting; for (int volume_idx = 0; volume_idx < this->volumes.size(); volume_idx++) { ModelVolume* volume = this->volumes[volume_idx]; @@ -2046,6 +2047,10 @@ void ModelObject::split(ModelObjectPtrs* new_objects) volume->text_configuration.reset(); if (!is_multi_volume_object) { + if (remap_paint) { + // Save painting so we could restore them after the mesh split + saved_painting = volume->save_painting(); + } //BBS: not multi volume object, then split mesh. std::vector volume_meshes = volume->mesh().split(); int mesh_count = 0; @@ -2123,6 +2128,9 @@ void ModelObject::split(ModelObjectPtrs* new_objects) COPY_FACETS(seam_facets); COPY_FACETS(mmu_segmentation_facets); COPY_FACETS(fuzzy_skin_facets); + } else if (saved_painting) { + // Geometry changed, attempt to remap them to the new mesh + new_vol->restore_painting(saved_painting); } // BBS: clear volume's config, as we already set them into object diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 5bf345607d..6a672defb0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -516,7 +516,7 @@ public: void delete_connectors(); void clone_for_cut(ModelObject **obj); - void split(ModelObjectPtrs*new_objects); + void split(ModelObjectPtrs*new_objects, bool remap_paint); void merge(); // BBS: Boolean opts - Musang King diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ec74a796e4..f78cc3f9b7 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7603,7 +7603,7 @@ void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */) wxBusyCursor wait; ModelObjectPtrs new_objects; - current_model_object->split(&new_objects); + current_model_object->split(&new_objects, wxGetApp().app_config->get_bool("keep_painting")); if (new_objects.size() == 1) // #ysFIXME use notification Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split.")); From fb0cf966cf5bd1ba77f6396204931d2a44b5718e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 17:06:19 +0800 Subject: [PATCH 016/127] Remap paint after split to parts --- src/libslic3r/Model.cpp | 7 ++++++- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 2 +- src/slic3r/Utils/FixModelByCgal.cpp | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 09751cd7df..586043bf4b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2731,7 +2731,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t) // Split this volume, append the result to the object owning this volume. // Return the number of volumes created from this one. // This is useful to assign different materials to different volumes of an object. -size_t ModelVolume::split(unsigned int max_extruders) +size_t ModelVolume::split(unsigned int max_extruders, bool remap_paint) { std::vector meshes = this->mesh().split(); if (meshes.size() <= 1) @@ -2741,6 +2741,9 @@ size_t ModelVolume::split(unsigned int max_extruders) if (text_configuration.has_value()) text_configuration.reset(); + std::optional saved_painting = remap_paint ? save_painting() : + std::optional{}; + size_t idx = 0; size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin(); const std::string name = this->name; @@ -2776,6 +2779,8 @@ size_t ModelVolume::split(unsigned int max_extruders) this->object->volumes[ivolume]->config.set("extruder", this->extruder_id()); //this->object->volumes[ivolume]->config.set("extruder", auto_extruder_id(max_extruders, extruder_counter)); this->object->volumes[ivolume]->m_is_splittable = 0; + this->object->volumes[ivolume]->restore_painting(saved_painting); + ++ idx; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 6a672defb0..fbe8da7b6a 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -930,7 +930,7 @@ public: // Split this volume, append the result to the object owning this volume. // Return the number of volumes created from this one. // This is useful to assign different materials to different volumes of an object. - size_t split(unsigned int max_extruders); + size_t split(unsigned int max_extruders, bool remap_paint); void translate(double x, double y, double z) { translate(Vec3d(x, y, z)); } void translate(const Vec3d& displacement); void scale(const Vec3d& scaling_factors); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 726ea1aca3..81a4791a0d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2849,7 +2849,7 @@ void ObjectList::split() take_snapshot("Split to parts"); - volume->split(filament_cnt); + volume->split(filament_cnt, wxGetApp().app_config->get_bool("keep_painting")); wxBusyCursor wait; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index bfc757589c..c2e4a19a73 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1908,7 +1908,7 @@ GLGizmoCut3D::PartSelection::PartSelection(const ModelObject* mo, const Transfor // split to parts for (int id = int(volumes.size())-1; id >= 0; id--) if (volumes[id]->is_splittable()) - volumes[id]->split(1); + volumes[id]->split(1, false); // TODO: fix this m_parts.clear(); for (const ModelVolume* volume : volumes) { diff --git a/src/slic3r/Utils/FixModelByCgal.cpp b/src/slic3r/Utils/FixModelByCgal.cpp index c014ceaf04..e1f4320fec 100644 --- a/src/slic3r/Utils/FixModelByCgal.cpp +++ b/src/slic3r/Utils/FixModelByCgal.cpp @@ -112,7 +112,7 @@ bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::Pro // Orca: Split splittable volumes into parts for individual processing. size_t parts_count = 1; if (volume->is_splittable()) { - parts_count = volume->split(1); + parts_count = volume->split(1, false); // TODO: fix this if (parts_count > 1) { const std::string msg = Slic3r::format(L("Split into %1% parts"), parts_count); on_progress(msg.c_str(), 10); From b3a513eab9a014e01def5c80e3958dc3fea0eaea Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 17:36:17 +0800 Subject: [PATCH 017/127] Remove redundent mmu facets assign because that's already done in `new_object->add_volume(*volume)` --- src/slic3r/GUI/GUI_ObjectList.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 81a4791a0d..0a8d0f480a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3041,7 +3041,6 @@ void ObjectList::merge(bool to_multipart_object) auto opt = object->config.option("extruder"); if (opt) { new_volume->config.set_key_value("extruder", new ConfigOptionInt(opt->getInt())); } } - new_volume->mmu_segmentation_facets.assign(std::move(volume->mmu_segmentation_facets)); } new_object->sort_volumes(true); From e6b3f6ccef662428a3c909c4f3769111333067f3 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 21:47:40 +0800 Subject: [PATCH 018/127] Add option to keep existing painting while mapping new paintings to it --- src/libslic3r/Model.cpp | 10 +++++++--- src/libslic3r/Model.hpp | 4 ++-- src/libslic3r/TriangleSelector.cpp | 7 ++++++- src/libslic3r/TriangleSelector.hpp | 4 +++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 586043bf4b..000ab997a9 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1995,7 +1995,7 @@ std::optional ModelVolume::save_painting() cons return {}; } -void ModelVolume::restore_painting(const std::optional& saved) +void ModelVolume::restore_painting(const std::optional& saved, const bool keep_existing_paint) { if (!saved) { return; @@ -2005,9 +2005,13 @@ void ModelVolume::restore_painting(const std::optionalmesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift())); + auto result = + TriangleSelector::remap_painting(saved->mesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift()), + keep_existing_paint ? + std::optional>{std::ref(target_facets.get_data())} : + std::optional>{}); if (!result.bitstream.empty()) - target_facets.set_data(result); + target_facets.set_data(std::move(result)); }; remap_one(saved->supported, supported_facets); remap_one(saved->seam, seam_facets); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index fbe8da7b6a..d8697adb41 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -731,7 +731,7 @@ public: void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } } void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } } const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; } - void set_data(const TriangleSelector::TriangleSplittingData &data) { m_data = data; this->touch(); } + void set_data(TriangleSelector::TriangleSplittingData &&data) { m_data = std::move(data); this->touch(); } bool set(const TriangleSelector& selector); indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const; // BBS @@ -884,7 +884,7 @@ public: std::optional save_painting() const; // Remap painting data from previous saved source to this mesh - void restore_painting(const std::optional& saved); + void restore_painting(const std::optional& saved, bool keep_existing_paint = false); // BBS: quick access for volume extruders, 1 based mutable std::vector mmuseg_extruders; diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 19f638a160..0fb1423df4 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -2407,7 +2407,8 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( const indexed_triangle_set& source_its, const TriangleSplittingData& source_painting, const indexed_triangle_set& target_its, - const Transform3d& target_transform) + const Transform3d& target_transform, + const std::optional>& existing_painting) { TriangleSelector::TriangleSplittingData result; if (source_painting.bitstream.empty()) @@ -2477,6 +2478,10 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( // 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it TriangleSelector target_selector(target_mesh); + if (existing_painting) { + // Restore existing painting first, if given + target_selector.deserialize(existing_painting->get(), false); + } for (auto tri_ref : painted_triangles) { const Triangle& tri = tri_ref.get(); const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v; diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 412c9fb9b1..09b606b5d2 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -383,11 +383,13 @@ public: // Remap painting data from source mesh to target mesh using spatial mapping. // `target_transform` should transform the target mesh into source's coordinate space. + // If `existing_painting` is present, the result will be a combine of `existing_painting` and remapped `source_painting`. static TriangleSplittingData remap_painting( const indexed_triangle_set& source_its, const TriangleSplittingData& source_painting, const indexed_triangle_set& target_its, - const Transform3d& target_transform); + const Transform3d& target_transform, + const std::optional>& existing_painting); protected: // Triangle and info about how it's split. From 3aadd6e0808e7aed0011f45d4c04b3230f4ef1d7 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 21:48:52 +0800 Subject: [PATCH 019/127] Remap paint after mesh boolean --- src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp | 32 +++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp | 4 ++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp index bfff70d315..c7186e5d80 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -188,6 +188,19 @@ CommonGizmosDataID GLGizmoMeshBoolean::on_get_requirements() const | int(CommonGizmosDataID::ObjectClipper)); } +std::optional VolumeInfo::save_painting() const +{ + if (wxGetApp().app_config->get_bool("keep_painting")) { + std::optional saved_painting = mv->save_painting(); + if (saved_painting) { + saved_painting->mesh.transform(trafo); + } + return saved_painting; + } + + return {}; +} + void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_limit) { y = std::min(y, bottom_limit - ImGui::GetWindowHeight()); @@ -346,7 +359,9 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l std::vector temp_mesh_resuls; Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "UNION"); if (temp_mesh_resuls.size() != 0) { - generate_new_volume(true, *temp_mesh_resuls.begin()); + // For union, we want to keep paint from both meshes + std::vector> saved_paintings{m_src.save_painting(), m_tool.save_painting()}; + generate_new_volume(true, *temp_mesh_resuls.begin(), saved_paintings); wxGetApp().notification_manager()->close_plater_warning_notification(warning_text); } else { @@ -364,7 +379,9 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l std::vector temp_mesh_resuls; Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "A_NOT_B"); if (temp_mesh_resuls.size() != 0) { - generate_new_volume(m_diff_delete_input, *temp_mesh_resuls.begin()); + // For diff, we only need paint from src + std::vector> saved_paintings{m_src.save_painting()}; + generate_new_volume(m_diff_delete_input, *temp_mesh_resuls.begin(), saved_paintings); wxGetApp().notification_manager()->close_plater_warning_notification(warning_text); } else { @@ -382,7 +399,9 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l std::vector temp_mesh_resuls; Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "INTERSECTION"); if (temp_mesh_resuls.size() != 0) { - generate_new_volume(m_inter_delete_input, *temp_mesh_resuls.begin()); + // For intersection, we want to keep paint from both meshes + std::vector> saved_paintings{m_src.save_painting(), m_tool.save_painting()}; + generate_new_volume(m_inter_delete_input, *temp_mesh_resuls.begin(), saved_paintings); wxGetApp().notification_manager()->close_plater_warning_notification(warning_text); } else { @@ -420,7 +439,7 @@ void GLGizmoMeshBoolean::on_save(cereal::BinaryOutputArchive &ar) const ar(m_enable, m_operation_mode, m_selecting_state, m_diff_delete_input, m_inter_delete_input, m_src, m_tool); } -void GLGizmoMeshBoolean::generate_new_volume(bool delete_input, const TriangleMesh& mesh_result) { +void GLGizmoMeshBoolean::generate_new_volume(const bool delete_input, TriangleMesh& mesh_result, const std::vector>& saved_paintings) { wxGetApp().plater()->take_snapshot("Mesh Boolean"); @@ -429,6 +448,11 @@ void GLGizmoMeshBoolean::generate_new_volume(bool delete_input, const TriangleMe // generate new volume ModelVolume* new_volume = curr_model_object->add_volume(std::move(mesh_result)); + // Remap paintings + for (const auto& saved_painting : saved_paintings) { + new_volume->restore_painting(saved_painting, true); + } + // assign to new_volume from old_volume ModelVolume* old_volume = m_src.mv; std::string suffix; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp index c012a68dca..9c36be5cd9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp @@ -34,6 +34,8 @@ struct VolumeInfo { void serialize(Archive& ar) { ar(volume_idx, trafo); } + + std::optional save_painting() const; }; class GLGizmoMeshBoolean : public GLGizmoBase { @@ -87,7 +89,7 @@ private: VolumeInfo m_src; VolumeInfo m_tool; - void generate_new_volume(bool delete_input, const TriangleMesh& mesh_result); + void generate_new_volume(bool delete_input, TriangleMesh& mesh_result, const std::vector>& saved_paintings); }; } // namespace GUI From f8a18e7656f2146b56cc3ae78d48690da7d88ad1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 00:41:18 +0800 Subject: [PATCH 020/127] Remap paint after mesh boolean (from context menu) --- src/slic3r/GUI/GUI_ObjectList.cpp | 39 +++++++++++++++++++++++++++++++ src/slic3r/GUI/Plater.cpp | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0a8d0f480a..9da5edf6c3 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3225,6 +3225,22 @@ void ObjectList::boolean() Plater::TakeSnapshot snapshot(wxGetApp().plater(), "boolean"); ModelObject* object = (*m_objects)[obj_idxs.front()]; + + const bool keep_painting = wxGetApp().app_config->get_bool("keep_painting"); + std::vector> saved_paintings; + if (keep_painting) { + // Save painting of all the positive parts + saved_paintings.reserve(object->volumes.size()); + for (const ModelVolume* vol : object->volumes) { + if (vol && vol->mesh_ptr() && vol->is_model_part() && vol->is_any_painted()) { + saved_paintings.emplace_back(vol->save_painting()); + if (saved_paintings.back()) { + saved_paintings.back()->mesh.transform(vol->get_matrix(), true); + } + } + } + } + TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [this](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); }); // add mesh to model as a new object, keep the original object's name and config @@ -3236,6 +3252,29 @@ void ObjectList::boolean() new_object->add_instance(); ModelVolume* new_volume = new_object->add_volume(mesh); + // Remap paint + if (keep_painting) { + for (auto& saved_painting : saved_paintings) { + if (saved_painting) { + // For each original painted volume, we need to apply to each instance + // because we merged all instances into one in `combine_mesh_fff` + + // First we save the non-instance-translated mesh + TriangleMesh vols_mesh(std::move(saved_painting->mesh)); + + for (const ModelInstance* i : object->instances) { + // Then for each instance, we apply the paint at the given instance place + saved_painting->mesh = vols_mesh; + saved_painting->mesh.transform(i->get_matrix()); + + // Then paint it + new_volume->restore_painting(saved_painting, true); + } + + } + } + } + // BBS: ensure on bed but no need to ensure locate in the center around origin new_object->ensure_on_bed(); new_object->center_around_origin(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f78cc3f9b7..e95d428248 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -15108,7 +15108,7 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st } if (instance_id == -1) { - TriangleMesh vols_mesh(mesh); + TriangleMesh vols_mesh(std::move(mesh)); mesh = TriangleMesh(); for (const ModelInstance* i : mo.instances) { TriangleMesh m = vols_mesh; From 219ef664bd0b7e53f280410410f97562c0d15226 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 11:45:15 +0800 Subject: [PATCH 021/127] Fix issue that in certain cases the paint is not applied when faces are parallel to an axis, by adding a small tolerance to the bbox --- src/libslic3r/TriangleSelector.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 0fb1423df4..93cb8747a6 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -2335,18 +2335,18 @@ public: // If both ends at the same side and farther than tolerance, skip const float dist_a = pts_dist[idx_a]; const float dist_b = pts_dist[idx_b]; - if ((dist_a > tolerance_ && dist_b > tolerance_) || (dist_a < -tolerance_ && dist_b < -tolerance_)) { + if ((dist_a > tolerance && dist_b > tolerance) || (dist_a < -tolerance && dist_b < -tolerance)) { continue; } // Find the projected line segment which has distance to the plane within the tolerance Vec3f pt_a = pts_proj[idx_a]; Vec3f pt_b = pts_proj[idx_b]; - if (std::abs(dist_a) > tolerance_) { - pt_a = (tolerance_ - dist_b) / (dist_a - dist_b) * (pts_proj[idx_a] - pts_proj[idx_b]) + pts_proj[idx_b]; + if (std::abs(dist_a) > tolerance) { + pt_a = (tolerance - dist_b) / (dist_a - dist_b) * (pts_proj[idx_a] - pts_proj[idx_b]) + pts_proj[idx_b]; } - if (std::abs(dist_b) > tolerance_) { - pt_b = (tolerance_ - dist_a) / (dist_b - dist_a) * (pts_proj[idx_b] - pts_proj[idx_a]) + pts_proj[idx_a]; + if (std::abs(dist_b) > tolerance) { + pt_b = (tolerance - dist_a) / (dist_b - dist_a) * (pts_proj[idx_b] - pts_proj[idx_a]) + pts_proj[idx_a]; } // If any projected end is inside the triangle, then is in @@ -2387,10 +2387,10 @@ public: return std::clamp(a, 0.f, 1.f) >= facet_angle_limit; } + static constexpr float tolerance = 0.01f; + private: const Barycentric barycentric_; - const float tolerance_ = EPSILON; - const float tolerance_sqr_ = tolerance_ * tolerance_; static const double facet_angle_limit; static float point_to_line_dist(const Vec3f& p, const Vec3f& a, const Vec3f& b) @@ -2494,6 +2494,8 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( pt_bbox.extend(pv0); pt_bbox.extend(pv1); pt_bbox.extend(pv2); + pt_bbox.min() -= Eigen::Vector3f::Constant(TriangleCursor::tolerance); + pt_bbox.max() += Eigen::Vector3f::Constant(TriangleCursor::tolerance); AABBTreeIndirect::traverse(target_tree, AABBTreeIndirect::intersecting(pt_bbox), [&](const AABBTreeIndirect::Tree3f::Node& node) -> bool { size_t face_idx = node.idx; From 73096a11611789ab8a4c092fdcc55520747a64c5 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 12:35:31 +0800 Subject: [PATCH 022/127] Fix artifact during normal paint --- src/libslic3r/TriangleSelector.cpp | 18 ++++++++++-------- src/libslic3r/TriangleSelector.hpp | 7 ++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 93cb8747a6..3b032cc57e 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -280,7 +280,7 @@ int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx) c return this->select_unsplit_triangle(hit, facet_idx, neighbors); } -void TriangleSelector::select_patch(int facet_start, std::unique_ptr &&cursor, EnforcerBlockerType new_state, const Transform3d& trafo_no_translate, bool triangle_splitting, float highlight_by_angle_deg) +void TriangleSelector::select_patch(int facet_start, std::unique_ptr &&cursor, EnforcerBlockerType new_state, const Transform3d& trafo_no_translate, bool triangle_splitting, float highlight_by_angle_deg, const bool select_partially) { assert(facet_start < m_orig_size_indices); @@ -343,7 +343,7 @@ void TriangleSelector::select_patch(int facet_start, std::unique_ptr &&c Matrix3f normal_matrix = static_cast(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast()); float world_normal_z = (normal_matrix* facet_normal).normalized().z(); if (!visited[facet] && (highlight_by_angle_deg == 0.f || world_normal_z < highlight_angle_limit)) { - if (select_triangle(facet, new_state, triangle_splitting)) { + if (select_triangle(facet, new_state, triangle_splitting, select_partially)) { // add neighboring facets to list to be processed later for (int neighbor_idx : m_neighbors[facet]) if (neighbor_idx >= 0 && m_cursor->is_facet_visible(neighbor_idx, m_face_normals)) @@ -599,7 +599,7 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ // This is done by an actual recursive call. Returns false if the triangle is // outside the cursor. // Called by select_patch() and by itself. -bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting) +bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting, bool select_partially) { assert(facet_idx < int(m_triangles.size())); @@ -609,7 +609,7 @@ bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, Vec3i32 neighbors = m_neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); - if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting)) + if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting, select_partially)) return false; // In case that all children are leafs and have the same state now, @@ -949,7 +949,7 @@ Vec3i32 TriangleSelector::child_neighbors_propagated(const Triangle &tr, const V return out; } -bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting) +bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting, bool select_partially) { assert(facet_idx < int(m_triangles.size())); @@ -982,8 +982,10 @@ bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i32 &n if (triangle_splitting) split_triangle(facet_idx, neighbors); - if (!m_triangles[facet_idx].is_split()) + if ((!triangle_splitting || select_partially) && !m_triangles[facet_idx].is_split()) { m_triangles[facet_idx].set_state(type); + return true; + } tr = &m_triangles[facet_idx]; // might have been invalidated by split_triangle(). int num_of_children = tr->number_of_split_sides() + 1; @@ -993,7 +995,7 @@ bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i32 &n assert(tr->children[i] < int(m_triangles.size())); // Recursion, deep first search over the children of this triangle. // All children of this triangle were created by splitting a single source triangle of the original mesh. - select_triangle_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), type, triangle_splitting); + select_triangle_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), type, triangle_splitting, select_partially); tr = &m_triangles[facet_idx]; // might have been invalidated } } @@ -2513,7 +2515,7 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting( if (TriangleCursor::check_normal(norm_b, -norm_a) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) { // Paint this face target_selector.select_patch(face_idx, TriangleCursor::build_cursor(source_selector, tri), tri.get_state(), - Transform3d::Identity(), true); + Transform3d::Identity(), true, 0.f, true); } return true; // continue traversal }); diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 09b606b5d2..11517f5c6c 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -308,7 +308,8 @@ public: EnforcerBlockerType new_state, // enforcer or blocker? const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation bool triangle_splitting, // If triangles will be split base on the cursor or not - float highlight_by_angle_deg = 0.f); // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. + float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. + bool select_partially = false); // Select a triangle if it's partially in the cursor but too small to be subdivided void seed_fill_select_triangles(const Vec3f &hit, // point where to start int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to @@ -496,8 +497,8 @@ protected: // Private functions: private: - bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting); - bool select_triangle_recursive(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting); + bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting, bool select_partially); + bool select_triangle_recursive(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting, bool select_partially); void undivide_triangle(int facet_idx); void split_triangle(int facet_idx, const Vec3i32 &neighbors); void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant. From 043a9f36d54252358a274ae685e6b1a117b88482 Mon Sep 17 00:00:00 2001 From: Bhall338 <23674868+brandonfhall@users.noreply.github.com> Date: Sun, 10 May 2026 03:09:57 -0400 Subject: [PATCH 023/127] Fix K2 family chamber temperature control defaults (#13399) K2 family printers set support_chamber_temp_control to true Co-authored-by: Copilot --- resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json | 2 +- .../profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Pro 0.2 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Pro 0.4 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Pro 0.6 nozzle.json | 1 + .../profiles/Creality/machine/Creality K2 Pro 0.8 nozzle.json | 1 + 12 files changed, 12 insertions(+), 4 deletions(-) diff --git a/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json index fd27ee8aa0..4cb1df1038 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json @@ -108,7 +108,7 @@ "silent_mode": "0", "single_extruder_multi_material": "1", "support_air_filtration": "1", - "support_chamber_temp_control": "0", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "thumbnails": [ "300x300", diff --git a/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json index d7b48c2e2a..ace8b15990 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json @@ -108,7 +108,7 @@ "silent_mode": "0", "single_extruder_multi_material": "1", "support_air_filtration": "1", - "support_chamber_temp_control": "0", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "thumbnails": [ "300x300", diff --git a/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json index 794243cf2c..d325dbcf52 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json @@ -108,7 +108,7 @@ "silent_mode": "0", "single_extruder_multi_material": "1", "support_air_filtration": "1", - "support_chamber_temp_control": "0", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "thumbnails": [ "300x300", diff --git a/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json index 3e565c6631..8b5f55c395 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json @@ -108,7 +108,7 @@ "silent_mode": "0", "single_extruder_multi_material": "1", "support_air_filtration": "1", - "support_chamber_temp_control": "0", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "thumbnails": [ "300x300", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json index d7b53e3f10..7e476f5430 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json index 8dcf873058..2a5d6523aa 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json index 95711bfb5c..1727eaf930 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json index 8706fe31da..8f3226d4dc 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Pro 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Pro 0.2 nozzle.json index 5de2a29548..4433c94b23 100644 --- a/resources/profiles/Creality/machine/Creality K2 Pro 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Pro 0.2 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Pro 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Pro 0.4 nozzle.json index 024d8616df..5b73723255 100644 --- a/resources/profiles/Creality/machine/Creality K2 Pro 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Pro 0.4 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Pro 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Pro 0.6 nozzle.json index e26fb461c2..4a9a1e2f24 100644 --- a/resources/profiles/Creality/machine/Creality K2 Pro 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Pro 0.6 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", diff --git a/resources/profiles/Creality/machine/Creality K2 Pro 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Pro 0.8 nozzle.json index b5d45d3b04..9db92a3cc6 100644 --- a/resources/profiles/Creality/machine/Creality K2 Pro 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Pro 0.8 nozzle.json @@ -23,6 +23,7 @@ "nozzle_volume": "183", "auxiliary_fan": "1", "support_air_filtration": "1", + "support_chamber_temp_control": "1", "support_multi_bed_types": "1", "machine_max_acceleration_e": [ "5000", From 5108b721a92a105c52600cb57ca14b7ba4abcfa9 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 10 May 2026 10:11:23 +0300 Subject: [PATCH 024/127] =?UTF-8?q?Fix=20=E2=80=9CJump=20to=E2=80=9D=20lin?= =?UTF-8?q?ks=20for=20non-print=20preset=20settings=20(#13381)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix "Jump to" links opening wrong preset type Fixes an issue where notification "Jump to" links always assumed the target setting belongs to the Print preset. Resolve the correct preset type for each option before jumping to it, and only switch to object settings when the target is a Print preset. Result: links now correctly open the intended setting across all preset types. --- src/slic3r/GUI/NotificationManager.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index c3209d052c..9875ae553b 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -9,6 +9,7 @@ #include "GUI_ObjectList.hpp" #include "ParamsPanel.hpp" #include "MainFrame.hpp" +#include "Tab.hpp" #include "libslic3r/Config.hpp" #include "format.hpp" @@ -111,6 +112,21 @@ namespace { } #endif } + + // Orca: Resolve the type of a validation option based on its key + Preset::Type resolve_validation_option_type(const std::string& opt_key) + { + if (opt_key.empty()) + return Preset::TYPE_PRINT; + + if (wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config()->def()->has(opt_key)) + return Preset::TYPE_PRINTER; + + if (wxGetApp().get_tab(Preset::TYPE_FILAMENT)->get_config()->def()->has(opt_key)) + return Preset::TYPE_FILAMENT; + + return Preset::TYPE_PRINT; + } } #if 1 @@ -1917,9 +1933,12 @@ void NotificationManager::push_validate_error_notification(StringObjectException } if (!opt.empty()) { - if ((!is_inst && id.id) || (is_inst && parent_id.id)) // if object found + const Preset::Type opt_type = resolve_validation_option_type(opt); + + if (opt_type == Preset::TYPE_PRINT && ((!is_inst && id.id) || (is_inst && parent_id.id))) // if object found and it's a print preset option, switch to object first wxGetApp().params_panel()->switch_to_object(); - wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L""); + + wxGetApp().sidebar().jump_to_option(opt, opt_type, L""); } else { wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); From 4e507fffb2952598fd5a092ff9d82f6608b994bb Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 10 May 2026 10:12:56 +0300 Subject: [PATCH 025/127] Fix support interface semantics, gap handling, behavior; fix bottom interface generation for organic trees; fix non organic tree interfaces (#11812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix support interface semantics and gap handling Fix zero-gap interface detection and gap initialization for supports and raft. Ensures correct top/bottom contact semantics and avoids relying on default zero gaps. * Additional fixes and robustness improvements Fix incorrect coupling between top and bottom support interface spacing and density, ensuring bottom interfaces use their own parameters for smoothing and toolpath generation. Restore correct bottom interface generation for organic (tree) supports when a non-zero bottom Z gap is used, and preserve contacts even when base polygons are empty. Improve robustness of organic support slicing by fixing layer index drift and guarding against degenerate polygon boolean operations. * Typo and semantics fix differnt_support_interface_filament -> different_support_interface_filament soluble -> zero_top_z_gap * Fix non organic tree bottom support interface generation Slim tree bottom interface layer numbers were capped by the object's layer number beneath it. Fixed by refactoring the generation algorithm. * Fix non organic tree interlaced support generation Deterministic local interlaced support layers generation for non-organic tree support * Enable support interface multimaterial for non organic tree Enables mixed-material support interface behavior for non organic tree support type. * Fix tree support interface layer counts and contact handling - Correct non‑organic tree top interface layer budgeting so gaps don’t consume a layer (N stays N). - Remove the extra roof interface pass that was duplicating the 2nd layer. - Organic tree: use only the lowest contact footprint and avoid extra bottom‑contact extrusion so interface count matches the user setting. * Bugfixes (a lot) Many, many bugs fixed, majority edge-case but still not playing by the rule. Some of them: - on multilevel base, on very small level variations the support was capped to the topmost level height - non-organic tree had gaps for supports in a multilevel base situiation - independent support layer height had issues with support interfaces (base support beneath bottom interface, top contact layer sometimes missing) - organic tree had issues with small variation multi-level base - organic tree support with zero top Z distance could overlap support-material and interface-material paths when separate materials were used - many, many others (I lost track of them) --- localization/i18n/OrcaSlicer.pot | 12 +- localization/i18n/ca/OrcaSlicer_ca.po | 24 +- localization/i18n/cs/OrcaSlicer_cs.po | 21 +- localization/i18n/de/OrcaSlicer_de.po | 23 +- localization/i18n/en/OrcaSlicer_en.po | 21 +- localization/i18n/es/OrcaSlicer_es.po | 22 +- localization/i18n/fr/OrcaSlicer_fr.po | 24 +- localization/i18n/hu/OrcaSlicer_hu.po | 29 +- localization/i18n/it/OrcaSlicer_it.po | 23 +- localization/i18n/ja/OrcaSlicer_ja.po | 24 +- localization/i18n/ko/OrcaSlicer_ko.po | 24 +- localization/i18n/lt/OrcaSlicer_lt.po | 24 +- localization/i18n/nl/OrcaSlicer_nl.po | 24 +- localization/i18n/pl/OrcaSlicer_pl.po | 24 +- localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 24 +- localization/i18n/ru/OrcaSlicer_ru.po | 24 +- localization/i18n/sv/OrcaSlicer_sv.po | 23 +- localization/i18n/tr/OrcaSlicer_tr.po | 24 +- localization/i18n/uk/OrcaSlicer_uk.po | 23 +- localization/i18n/vi/OrcaSlicer_vi.po | 25 +- localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 20 +- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 22 +- src/libslic3r/Layer.hpp | 1 + src/libslic3r/PrintConfig.cpp | 10 +- src/libslic3r/Slicing.cpp | 117 +++++-- src/libslic3r/Slicing.hpp | 13 +- src/libslic3r/Support/SupportCommon.cpp | 80 ++++- src/libslic3r/Support/SupportMaterial.cpp | 16 +- src/libslic3r/Support/SupportMaterial.hpp | 2 +- src/libslic3r/Support/SupportParameters.hpp | 92 ++--- src/libslic3r/Support/TreeSupport.cpp | 367 ++++++++++++++++---- src/libslic3r/Support/TreeSupport3D.cpp | 331 +++++++++++------- src/libslic3r/Support/TreeSupportCommon.hpp | 12 +- 33 files changed, 1098 insertions(+), 447 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 33d9dbb407..13c581ab18 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -14212,7 +14212,10 @@ msgstr "" msgid "Raft contact Z distance" msgstr "" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" msgid "Raft expansion" @@ -14983,13 +14986,16 @@ msgstr "" msgid "Top Z distance" msgstr "" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "" msgid "Bottom Z distance" msgstr "" -msgid "The Z gap between the bottom support interface and object." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." msgstr "" msgid "Support/raft base" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index 768d46bd79..c8a44d1039 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -16647,10 +16647,14 @@ msgstr "Model d'impressora" msgid "Raft contact Z distance" msgstr "Distància Z de contacte de la Vora d'Adherència" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Distància Z entre l'objecte i la Vora d'Adherència. S'ignorarà per a " -"interfície soluble" +"Espai Z entre la vora d'Adherència i l'objecte. " +"Si la distància Z superior del suport és 0, aquest valor s'ignora i l'objecte " +"s'imprimeix en contacte directe amb la vora d'Adherència (sense espai)." msgid "Raft expansion" msgstr "Expansió de la Vora d'Adherència" @@ -17631,14 +17635,20 @@ msgstr "Ignora els voladissos petits que possiblement no requereixen suport." msgid "Top Z distance" msgstr "Distància Z superior" -msgid "The Z gap between the top support interface and object." -msgstr "La distància z entre la interfície de suport superior i l'objecte" +msgid "Z gap between the support's top and object." +msgstr "Espai Z entre la part superior del suport i l'objecte." msgid "Bottom Z distance" msgstr "Distància Z inferior" -msgid "The Z gap between the bottom support interface and object." -msgstr "La distància z entre la interfície de suport inferior i l'objecte" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Espai Z entre l'objecte i la part inferior del suport. " +"Si la distància Z superior del suport és 0 i la part inferior té capes d'interfície, aquest " +"valor s'ignora i el suport s'imprimeix en contacte directe amb l'objecte (sense espai)." msgid "Support/raft base" msgstr "Base del Suport/Vora d'Adherència" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 6755d2502f..46366b4f15 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -16181,9 +16181,14 @@ msgstr "Varianta tiskárny" msgid "Raft contact Z distance" msgstr "Z vzdálenost kontaktu raftu" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Z mezera mezi objektem a raftem. Ignorováno pro rozpustitelné rozhraní." +"Z mezera mezi raftem a objektem. " +"Pokud je Horní Z vzdálenost podpory 0, tato hodnota se ignoruje " +"a objekt se tiskne v přímém kontaktu s raftem (bez mezery)." msgid "Raft expansion" msgstr "Rozšíření raftu" @@ -17134,14 +17139,20 @@ msgstr "Ignore small overhangs that possibly don't require support." msgid "Top Z distance" msgstr "Horní vzdálenost v ose Z" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "Z mezera mezi horním rozhraním podpory a objektem." msgid "Bottom Z distance" msgstr "Spodní vzdálenost v ose Z" -msgid "The Z gap between the bottom support interface and object." -msgstr "Z mezera mezi spodním rozhraním podpory a objektem." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z mezera mezi spodním rozhraním podpory a objektem. " +"Pokud je Horní Z vzdálenost podpory 0 a spodek má vrstvy rozhraní, tato hodnota " +"se ignoruje a podpora se tiskne v přímém kontaktu s objektem (bez mezery)." msgid "Support/raft base" msgstr "Podpora/základ raftu" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 26a85806e3..e2b74f5eb3 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -16767,9 +16767,14 @@ msgstr "Druckervariante" msgid "Raft contact Z distance" msgstr "Z Abstand Objekt Druckbasis " -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Z-Abstand zwischen Objekt und Druckbasis. Bei löslicher Oberfläche ignoriert" +"Z-Abstand zwischen Druckbasis (Raft) und Objekt. " +"Wenn der obere Z-Abstand der Stützen ist 0, wird dieser Wert ignoriert und das " +"Objekt wird in direktem Kontakt mit der Druckbasis (Raft) gedruckt (kein Abstand)." msgid "Raft expansion" msgstr "Druckbasis Erweiterung" @@ -17744,14 +17749,20 @@ msgstr "" msgid "Top Z distance" msgstr "Oberer Z-Abstand" -msgid "The Z gap between the top support interface and object." -msgstr "Der Z-Abstand zwischen der oberen Stütz-Schnittstelle und dem Objekt" +msgid "Z gap between the support's top and object." +msgstr "Z-Abstand zwischen der Oberseite der Stützen und dem Objekt." msgid "Bottom Z distance" msgstr "Unterer Z-Abstand" -msgid "The Z gap between the bottom support interface and object." -msgstr "Der Z-Abstand zwischen der unteren Stütz-Schnittstelle und dem Objekt" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z-Abstand zwischen dem Objekt und der Unterseite der Stützen. " +"Wenn der obere Z-Abstand der Stützen ist 0 und die Unterseite Schnittstellenschichten hat, wird dieser " +"Wert ignoriert und die Stützen werden in direktem Kontakt mit dem Objekt gedruckt (kein Abstand)." msgid "Support/raft base" msgstr "Stütz-/Basis-Objekt" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 1103146ce0..74c57e579c 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -14527,10 +14527,13 @@ msgstr "" msgid "Raft contact Z distance" msgstr "" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"This is the Z gap between an object and a raft. It is ignored for soluble " -"interfaces." +"Z gap between raft and object. If Support Top Z Distance is 0, this value " +"is ignored and the object is printed in direct contact with the raft (no gap)." msgid "Raft expansion" msgstr "" @@ -15325,14 +15328,20 @@ msgstr "" msgid "Top Z distance" msgstr "" -msgid "The Z gap between the top support interface and object." -msgstr "This determines the Z gap between top support interfaces and objects." +msgid "Z gap between the support's top and object." +msgstr "Z gap between the support's top and object." msgid "Bottom Z distance" msgstr "" -msgid "The Z gap between the bottom support interface and object." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." msgstr "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." msgid "Support/raft base" msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index c52a64f72a..4951eadd34 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -16713,10 +16713,14 @@ msgstr "Variante de la impresora" msgid "Raft contact Z distance" msgstr "Distancia Z de contacto de la balsa (base de impresión)" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Espacio Z entre el objeto y la balsa (base de impresión). Se ignora con una " -"interfaz soluble." +"Espacio Z entre el objeto y la balsa (base de impresión). " +"Si la distancia Z superior del soporte es 0, este valor se ignora y el " +"objeto se imprime en contacto directo con la balsa (sin separación)." msgid "Raft expansion" msgstr "Expansión de la balsa (base de impresión)" @@ -17704,14 +17708,20 @@ msgstr "Ignorar pequeños voladizos que posiblemente no requieran soporte." msgid "Top Z distance" msgstr "Distancia Z superior" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "La distancia z entre la interfaz de soporte superior y el objeto." msgid "Bottom Z distance" msgstr "Distancia Z inferior" -msgid "The Z gap between the bottom support interface and object." -msgstr "La distancia z entre la interfaz de apoyo inferior y el objeto." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"La distancia z entre la interfaz de apoyo inferior y el objeto. " +"Si la distancia Z superior del soporte es 0 y la base tiene capas de interfaz, este valor " +"se ignora y el soporte se imprime en contacto directo con el objeto (sin separación)." msgid "Support/raft base" msgstr "Capa base/balsa" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index c7e9d3f354..42336db6a9 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -16872,8 +16872,14 @@ msgstr "Variante de l’imprimante" msgid "Raft contact Z distance" msgstr "Distance Z de contact du radeau" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "Écart en Z entre l'objet et le radeau. Ignoré pour l'interface soluble" +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "" +"Écart Z entre le radeau et l'objet. " +"Si la distance Z supérieure du support est 0, cette valeur est ignorée " +"et l'objet est imprimé en contact direct avec le radeau (sans écart)." msgid "Raft expansion" msgstr "Agrandissement du radeau" @@ -17870,14 +17876,20 @@ msgstr "" msgid "Top Z distance" msgstr "Distance Z supérieure" -msgid "The Z gap between the top support interface and object." -msgstr "L'écart z entre l'interface de support supérieure et l'objet" +msgid "Z gap between the support's top and object." +msgstr "Écart Z entre le haut du support et l'objet." msgid "Bottom Z distance" msgstr "Distance Z inférieure" -msgid "The Z gap between the bottom support interface and object." -msgstr "L'écart Z entre l'interface du support inférieur et l'objet" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Écart Z entre l'objet et le bas du support. " +"Si la distance Z supérieure du support est 0 et que le bas a des couches d'interface, cette " +"valeur est ignorée et le support est imprimé en contact direct avec l'objet (sans écart)." msgid "Support/raft base" msgstr "Support/base du radeau" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index d4660b0ec6..dffa28be51 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -16520,10 +16520,14 @@ msgstr "Nyomtató változat" msgid "Raft contact Z distance" msgstr "Tutaj érintkezési Z-távolság" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"This is the Z gap between an object and a raft. It is ignored for soluble " -"interfaces." +"Z rés a tutaj és a tárgy között. " +"Ha a támasz felső Z-távolsága 0, ez az érték figyelmen kívül lesz " +"hagyva és a tárgy közvetlenül a tutajon kerül nyomtatásra (rés nélkül)." msgid "Raft expansion" msgstr "Tutaj kibővítése" @@ -17510,19 +17514,24 @@ msgstr "" msgid "Top Z distance" msgstr "Z távolság" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "" -"Meghatározza a Z távolságot a felső támasz érintkező rétege és az objektum " -"között." +"Z rés a támasz teteje és a tárgy között." msgid "Bottom Z distance" msgstr "Alsó Z távolság" -msgid "The Z gap between the bottom support interface and object." -msgstr "A Z távolság az alsó támasz érintkező rétege és az objektum között." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z rés a tárgy és a támasz alja között. " +"Ha a támasz felső Z-távolsága 0 és az alján vannak interfész rétegek, ez az érték " +"figyelmen kívül lesz hagyva, és a támasz közvetlenül a tárgyhoz lesz nyomtatva (rés nélkül)." msgid "Support/raft base" -msgstr "Támaszték/tutaj alap" +msgstr "Támasz/tutaj alap" msgid "" "Filament to print support base and raft. \"Default\" means no specific " @@ -17558,7 +17567,7 @@ msgstr "" "letiltva." msgid "Support/raft interface" -msgstr "Támaszték/tutaj csatlakozófelület" +msgstr "Támasz/tutaj interfész" msgid "" "Filament to print support interface. \"Default\" means no specific filament " diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index f49ac5711a..ae9e26387a 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -16748,10 +16748,14 @@ msgstr "Variante stampante" msgid "Raft contact Z distance" msgstr "Distanza Z di contatto zattera" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Indica lo spazio Z tra oggetto e zattera. Viene ignorato per le interfacce " -"di supporto solubili." +"Spazio Z tra zattera e oggetto. " +"Se la distanza Z superiore del supporto è 0, questo valore viene ignorato e " +"l'oggetto viene stampato a contatto diretto con la zattera (senza spazio)." msgid "Raft expansion" msgstr "Espansione della zattera" @@ -17745,16 +17749,21 @@ msgstr "Ignora i piccoli sbalzi che potrebbero non richiedere supporto." msgid "Top Z distance" msgstr "Distanza Z superiore" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "" -"Determina lo spazio Z tra l'interfaccia di supporto superiore e l'oggetto." +"Spazio Z tra la parte superiore del supporto e l'oggetto." msgid "Bottom Z distance" msgstr "Distanza Z inferiore" -msgid "The Z gap between the bottom support interface and object." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." msgstr "" -"Determina lo spazio Z tra l'interfaccia di supporto inferiore e l'oggetto." +"Spazio Z tra l'oggetto e la base del supporto. " +"Se la distanza Z superiore del supporto è 0 e la base ha strati di interfaccia, questo valore " +"viene ignorato e il supporto viene stampato a contatto diretto con l'oggetto (senza spazio)." msgid "Support/raft base" msgstr "Base supporto/zattera" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 0b1d6d4f4a..ba6af3b17a 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -15234,10 +15234,14 @@ msgstr "プリンターバリエーション" msgid "Raft contact Z distance" msgstr "ラフト接触面Z間隔" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"ラフトとオブジェクトのZ方向の間隔。可溶性材料を使用する場合この設定が無効で" -"す。" +"ラフトとオブジェクトの間のZ隙間。" +"サポート上面Z距離が0の場合、この値は無視され、" +"オブジェクトはラフトに直接接触して印刷されます(隙間なし)。" msgid "Raft expansion" msgstr "ラフト拡張" @@ -16046,14 +16050,20 @@ msgstr "" msgid "Top Z distance" msgstr "トップ面とのZ間隔" -msgid "The Z gap between the top support interface and object." -msgstr "サポート接触面とオブジェクトのZ方向の間隔" +msgid "Z gap between the support's top and object." +msgstr "サポート上面とオブジェクトの間のZ隙間。" msgid "Bottom Z distance" msgstr "底面とのZ間隔" -msgid "The Z gap between the bottom support interface and object." -msgstr "サポート底面とオブジェクトのZ方向間隔" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"オブジェクトとサポート下面の間のZ隙間。" +"サポート上面Z距離が0で、下面にインターフェース層がある場合、" +"この値は無視され、サポートはオブジェクトに直接接触して印刷されます(隙間なし)。" msgid "Support/raft base" msgstr "" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index 85d1925bf6..d8f1a9a476 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -15509,8 +15509,14 @@ msgstr "프린터 변형" msgid "Raft contact Z distance" msgstr "라프트 접점 Z 거리" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "객체와 라프트 사이의 Z 거리. 가용성 재료의 접점은 무시됨" +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "" +"래프트와 객체 사이의 Z 간격. " +"서포트 상단 Z 거리가 0이면 이 값은 무시되고 " +"객체는 래프트에 직접 접촉하여 출력됩니다(간격 없음)." msgid "Raft expansion" msgstr "라프트 확장" @@ -16426,14 +16432,20 @@ msgstr "" msgid "Top Z distance" msgstr "상단 Z 거리" -msgid "The Z gap between the top support interface and object." -msgstr "서포트 상단과 객체 접점의 간격" +msgid "Z gap between the support's top and object." +msgstr "서포트 상단과 객체 사이의 Z 간격." msgid "Bottom Z distance" msgstr "하단 Z 거리" -msgid "The Z gap between the bottom support interface and object." -msgstr "서포트 하단과 객체 접점의 간격" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"객체와 서포트 하단 사이의 Z 간격. " +"서포트 상단 Z 거리가 0이고 하단에 인터페이스 레이어가 있으" +"면 이 값은 무시되고 서포트가 객체에 직접 접촉하여 출력됩니다(간격 없음)." msgid "Support/raft base" msgstr "서포트/라프트 기본" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 0245eb9b3d..e0ae114829 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -16435,10 +16435,14 @@ msgstr "Spausdintuvo variantas" msgid "Raft contact Z distance" msgstr "Platformos kontakto Z atstumas" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Z tarpas tarp objekto ir platformos. Į jį neatsižvelgiama tirpių sąsajų " -"atveju." +"Z tarpas tarp platformos ir objekto. " +"Jei viršutinis atramos Z atstumas yra 0, ši reikšmė ignoruojama ir " +"objektas spausdinamas tiesiogiai kontaktuojant su platforma (be tarpo)." msgid "Raft expansion" msgstr "Platformos išplėtimas" @@ -17408,14 +17412,20 @@ msgstr "Ignore small overhangs that possibly don't require support." msgid "Top Z distance" msgstr "Viršutinis Z atstumas" -msgid "The Z gap between the top support interface and object." -msgstr "Taip nustatomas Z tarpas tarp viršutinių atramų sąsajų ir objektų." +msgid "Z gap between the support's top and object." +msgstr "Z tarpas tarp atramos viršaus ir objekto." msgid "Bottom Z distance" msgstr "Apatinis Z atstumas" -msgid "The Z gap between the bottom support interface and object." -msgstr "Z tarpas tarp apatinės atramos sąsajos ir objekto." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z tarpas tarp objekto ir atramos apačios. " +"Jei viršutinis atramos Z atstumas yra 0 ir apačioje yra sąsajos sluoksniai, ši reikšmė " +"ignoruojama ir atrama spausdinama tiesiogiai kontaktuojant su objektu (be tarpo)." msgid "Support/raft base" msgstr "Atraminis ir (arba) platformos pagrindas" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 1dec100c62..758d0bf066 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -16429,10 +16429,14 @@ msgstr "Printervariant" msgid "Raft contact Z distance" msgstr "Vlot (raft) contact Z afstand:" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Dit is de Z-afstand tussen een object en een raft. Het wordt genegeerd voor " -"oplosbare materialen." +"Z-gap tussen het vlot en het object. " +"Als de bovenste Z-afstand van de ondersteuning 0 is, wordt deze waarde " +"genegeerd en wordt het object direct in contact met het vlot geprint (geen gap)." msgid "Raft expansion" msgstr "Vlot (raft) expansie" @@ -17407,15 +17411,21 @@ msgstr "Ignore small overhangs that possibly don't require support." msgid "Top Z distance" msgstr "Top Z afstand" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "" -"Dit bepaald de Z-afstand tussen de bovenste support interfaces en het object." +"Z-gap tussen de bovenkant van de ondersteuning en het object." msgid "Bottom Z distance" msgstr "Onderste Z-afstand" -msgid "The Z gap between the bottom support interface and object." -msgstr "De z-opening tussen de onderste ondersteuningsinterface en het object" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z-gap tussen het object en de onderkant van de ondersteuning. " +"Als de bovenste Z-afstand van de ondersteuning 0 is en de onderkant interfacerlagen heeft, wordt " +"deze waarde genegeerd en wordt de ondersteuning direct in contact met het object geprint (geen gap)." msgid "Support/raft base" msgstr "Support/raft base" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index fefb91e288..8de15512c2 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -15876,10 +15876,14 @@ msgstr "Wariant drukarki" msgid "Raft contact Z distance" msgstr "Odległość Z kontaktu z tratwą" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Dystans między modelem, a raftem, mierzony w poziomie. Ignorowany dla " -"rozpuszczalnych warstw łączących" +"Odstęp Z między tratwą a obiektem. " +"Jeśli górny odstęp Z podpór wynosi 0, ta wartość jest ignorowana i " +"obiekt jest drukowany w bezpośrednim kontakcie z tratwą (bez odstępu)." msgid "Raft expansion" msgstr "Rozszerzenie tratwy" @@ -16846,14 +16850,20 @@ msgstr "" msgid "Top Z distance" msgstr "Odstęp góry w osi Z" -msgid "The Z gap between the top support interface and object." -msgstr "Odstęp osi Z między górną warstwą łączącą podporę z obiektem" +msgid "Z gap between the support's top and object." +msgstr "Odstęp Z między górą podpór a obiektem." msgid "Bottom Z distance" msgstr "Odstęp spodu w osi Z" -msgid "The Z gap between the bottom support interface and object." -msgstr "Odległość w osi Z między dolną warstwą łączącyą a obiektem" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Odstęp Z między obiektem a dołem podpór. " +"Jeśli górny odstęp Z podpór wynosi 0 i dół ma warstwy interfejsu, ta wartość jest " +"ignorowana, a podpory są drukowane w bezpośrednim kontakcie z obiektem (bez odstępu)." msgid "Support/raft base" msgstr "Podstawa podpory/tratwy" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 47c06c471c..221a4e0e77 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -16596,8 +16596,14 @@ msgstr "Variante da impressora" msgid "Raft contact Z distance" msgstr "Distância Z de contato da jangada" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "Vão Z entre o objeto e a jangada. Ignorado para interface solúvel." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "" +"Espaço Z entre a balsa e o objeto. " +"Se a Distância Z Superior do Suporte for 0, este valor é ignorado " +"e o objeto é impresso em contato direto com a balsa (sem espaço)." msgid "Raft expansion" msgstr "Expansão da jangada" @@ -17575,14 +17581,20 @@ msgstr "Ignorar pequenas saliências que possivelmente não requerem suporte." msgid "Top Z distance" msgstr "Distância Z superior" -msgid "The Z gap between the top support interface and object." -msgstr "O vão Z entre a interface superior de suporte e o objeto." +msgid "Z gap between the support's top and object." +msgstr "Espaço Z entre o topo do suporte e o objeto." msgid "Bottom Z distance" msgstr "Distância Z inferior" -msgid "The Z gap between the bottom support interface and object." -msgstr "O vão Z entre a interface inferior de suporte e o objeto." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Espaço Z entre o objeto e a base do suporte. " +"Se a Distância Z Superior do Suporte for 0 e a base tiver camadas de interface, este " +"valor é ignorado e o suporte é impresso em contato direto com o objeto (sem espaço)." msgid "Support/raft base" msgstr "Base de suporte/jangada" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index 4998ad9034..43b04bf565 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -16957,10 +16957,14 @@ msgstr "Модификация принтера" msgid "Raft contact Z distance" msgstr "Зазор под моделью" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Вертикальное расстояние между подложкой и моделью. Значение игнорируется при " -"выборе растворимого материала." +"Вертикальное расстояние между подложкой и моделью. " +"Если зазор поддержки сверху равен 0, это значение игнорируется, " +"и модель печатается в прямом контакте с подложкой (без зазора)." msgid "Raft expansion" msgstr "Расширение подложки" @@ -18050,16 +18054,20 @@ msgstr "" msgid "Top Z distance" msgstr "Зазор поддержки сверху" -msgid "The Z gap between the top support interface and object." -msgstr "" -"Вертикальное расстояние между связующим слоем поддержки сверху и моделью." +msgid "Z gap between the support's top and object." +msgstr "Вертикальное расстояние между связующим слоем поддержки сверху и моделью." msgid "Bottom Z distance" msgstr "Зазор поддержки снизу" -msgid "The Z gap between the bottom support interface and object." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." msgstr "" -"Вертикальное расстояние между связующим слоем поддержки снизу и моделью." +"Вертикальное расстояние между связующим слоем поддержки снизу и моделью. " +"Если зазор поддержки сверху равен 0 и снизу есть интерфейсные слои, это значение " +"игнорируется, и поддержка печатается в прямом контакте с моделью (без зазора)." msgid "Support/raft base" msgstr "Поддержка/подложка" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index d3665b412b..e4afd775dc 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -16258,10 +16258,14 @@ msgstr "Printer variant" msgid "Raft contact Z distance" msgstr "Raft kontakt Z avstånd" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Där finns Z mellanrum mellan ett objekt och en raft. Detta ignoreras för " -"lösliga gränssnitt" +"Z-gapet mellan raften och objektet. " +"Om Topp Z-distans är 0 ignoreras detta värde och objektet " +"skrivs ut i direkt kontakt med raften (utan mellanrum)." msgid "Raft expansion" msgstr "Raft expansion" @@ -17222,15 +17226,20 @@ msgstr "Ignore small overhangs that possibly don't require support." msgid "Top Z distance" msgstr "Topp Z-distans" -msgid "The Z gap between the top support interface and object." +msgid "Z gap between the support's top and object." msgstr "" -"Detta bestämmer Z-avståndet mellan det övre support gränssnittet och objektet" +"Z-gapet mellan supportens topp och objektet." msgid "Bottom Z distance" msgstr "Nedre Z-avstånd" -msgid "The Z gap between the bottom support interface and object." -msgstr "Z-gapet mellan botten support och objektets anläggningsyta" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "Z-gapet mellan objektet och supportens botten. " +"Om Topp Z-distans är 0 och botten har gränssnittslager ignoreras detta " +"värde och supporten skrivs ut i direkt kontakt med objektet (utan mellanrum)." msgid "Support/raft base" msgstr "Support/raft bas" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 1739550e07..7213477c1f 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -14490,8 +14490,14 @@ msgstr "Yazıcı çeşidi" msgid "Raft contact Z distance" msgstr "Raft kontak Z mesafesi" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "Nesne ve raft arasındaki Z boşluğu. Çözünür arayüz için göz ardı edildi." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "" +"Sal ile nesne arasındaki Z boşluğu. " +"Destek üst Z mesafesi 0 ise bu değer yok sayılır ve nesne " +"sal ile doğrudan temas halinde basılır (boşluk yok)." msgid "Raft expansion" msgstr "Raft genişletme" @@ -15274,14 +15280,20 @@ msgstr "Muhtemelen destek gerektirmeyen küçük çıkıntıları göz ardı edi msgid "Top Z distance" msgstr "Üst z mesafesi" -msgid "The Z gap between the top support interface and object." -msgstr "Üst destek arayüzü ile nesne arasındaki z boşluğu." +msgid "Z gap between the support's top and object." +msgstr "Desteğin üstü ile nesne arasındaki Z boşluğu." msgid "Bottom Z distance" msgstr "Alt z mesafesi" -msgid "The Z gap between the bottom support interface and object." -msgstr "Alt destek arayüzü ile nesne arasındaki z boşluğu." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Nesne ile destek altı arasındaki Z boşluğu. " +"Destek üst Z mesafesi 0 ise ve altta arayüz katmanları varsa bu değer yok " +"sayılır ve destek nesneyle doğrudan temas halinde basılır (boşluk yok)." msgid "Support/raft base" msgstr "Destek/raft tabanı" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 99466c46dc..23737951fa 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -15868,9 +15868,14 @@ msgstr "Варіант принтера" msgid "Raft contact Z distance" msgstr "Відстань Z контакту підкладки" -msgid "Z gap between object and raft. Ignored for soluble interface." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." msgstr "" -"Зазор Z між об'єктом та підкладкою. Ігнорується для розчинного інтерфейсу" +"Z-зазор між підкладкою та моделлю. " +"Якщо верхній Z-зазор підтримки дорівнює 0, це значення ігнорується, " +"і модель друкується в прямому контакті з підкладкою (без зазору)." msgid "Raft expansion" msgstr "Розширення підкладки" @@ -16823,14 +16828,20 @@ msgstr "" msgid "Top Z distance" msgstr "Верхня відстань Z" -msgid "The Z gap between the top support interface and object." -msgstr "Зазор осі z між верхом підтримки та об'єктом" +msgid "Z gap between the support's top and object." +msgstr "Z-зазор між верхом підтримки та моделлю." msgid "Bottom Z distance" msgstr "Нижня відстань Z" -msgid "The Z gap between the bottom support interface and object." -msgstr "Зазор осі z між низом підтримки та об'єктом" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Z-зазор між моделлю та нижньою частиною підтримки. " +"Якщо верхній Z-зазор підтримки дорівнює 0 і знизу є інтерфейсні шари, це значення " +"ігнорується, і підтримка друкується в прямому контакті з моделлю (без зазору)." msgid "Support/raft base" msgstr "База підтримки/підкладки" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index c48d08f9cb..11c089e45c 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -16082,8 +16082,14 @@ msgstr "Biến thể máy in" msgid "Raft contact Z distance" msgstr "Khoảng cách Z tiếp xúc raft" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "Khe Z giữa đối tượng và raft. Bị bỏ qua cho giao diện hòa tan." +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "" +"Khoảng cách Z giữa bè và vật thể. " +"Nếu khoảng cách Z trên của hỗ trợ bằng 0, giá trị này sẽ bị bỏ qua " +"và vật thể được in tiếp xúc trực tiếp với bè (không có khe hở)." msgid "Raft expansion" msgstr "Mở rộng raft" @@ -17024,14 +17030,20 @@ msgstr "Ignore small overhangs that possibly don't require support." msgid "Top Z distance" msgstr "Khoảng cách Z trên" -msgid "The Z gap between the top support interface and object." -msgstr "Khe Z giữa giao diện support trên và đối tượng." +msgid "Z gap between the support's top and object." +msgstr "Khoảng cách Z giữa mặt trên của hỗ trợ và vật thể." msgid "Bottom Z distance" msgstr "Khoảng cách Z dưới" -msgid "The Z gap between the bottom support interface and object." -msgstr "Khe Z giữa giao diện support dưới và đối tượng." +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"Khoảng cách Z giữa vật thể và phần đáy của hỗ trợ. " +"Nếu khoảng cách Z trên của hỗ trợ bằng 0 và phần đáy có các lớp giao diện, giá trị " +"này sẽ bị bỏ qua và hỗ trợ được in tiếp xúc trực tiếp với vật thể (không có khe hở)." msgid "Support/raft base" msgstr "Đế support/raft" @@ -22875,3 +22887,4 @@ msgstr "" #, c-format, boost-format #~ msgid "*Printing %s material with %s may cause nozzle damage" #~ msgstr "*In vật liệu %s với %s có thể gây hư hỏng đầu phun" + diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 85e2f49a05..9d662abb3c 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -15131,8 +15131,11 @@ msgstr "打印机变种" msgid "Raft contact Z distance" msgstr "筏层Z间距" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "模型和筏层之间的Z间隙" +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "筏层与模型之间的Z间隙。如果支撑顶部Z距离为0,则忽略该值,模型与筏层直接接触打印(无间隙)。" msgid "Raft expansion" msgstr "筏层扩展" @@ -15991,14 +15994,19 @@ msgstr "将几乎不需要支撑的微小悬垂忽略掉。" msgid "Top Z distance" msgstr "顶部Z距离" -msgid "The Z gap between the top support interface and object." -msgstr "支撑顶部和模型之间的z间隙" +msgid "Z gap between the support's top and object." +msgstr "支撑顶部与模型之间的Z间隙。" msgid "Bottom Z distance" msgstr "底部Z距离" -msgid "The Z gap between the bottom support interface and object." -msgstr "支撑生成于模型表面时,支撑面底部和模型之间的z间隙" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"模型与支撑底部之间的Z间隙。" +"如果支撑顶部Z距离为0且底部有界面层,则忽略该值,支撑与模型直接接触打印(无间隙)。" msgid "Support/raft base" msgstr "支撑/筏层主体" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 12fc980c8f..98997731cb 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -4152,7 +4152,7 @@ msgstr "" "重設為 0。seam_slope_start_height 必須小於 layer_height。\n" "重設為 0。" -#, no-c-format, no-boost-format +#, fuzzy, c-format, boost-format msgid "" "Lock depth should smaller than skin depth.\n" "Reset to 50% of skin depth." @@ -15263,8 +15263,11 @@ msgstr "列印設備型號" msgid "Raft contact Z distance" msgstr "筏層 Z 間距" -msgid "Z gap between object and raft. Ignored for soluble interface." -msgstr "模型和筏層之間的Z間隙" +msgid "" +"Z gap between raft and object. " +"If Support Top Z Distance is 0, this value is ignored and " +"the object is printed in direct contact with the raft (no gap)." +msgstr "筏層與模型之間的Z間隙。若支撐頂部Z距離為0,則忽略此值,模型與筏層直接接觸列印(無間隙)。" msgid "Raft expansion" msgstr "筏層擴展" @@ -16127,14 +16130,19 @@ msgstr "將幾乎不需要支撐的微小懸空忽略掉。" msgid "Top Z distance" msgstr "頂部 Z 間距" -msgid "The Z gap between the top support interface and object." -msgstr "支撐頂部和模型之間的 Z 間隙" +msgid "Z gap between the support's top and object." +msgstr "支撐頂部與模型之間的Z間隙。" msgid "Bottom Z distance" msgstr "底部 Z 間距" -msgid "The Z gap between the bottom support interface and object." -msgstr "支撐產生於模型表面時,支撐面底部和模型之間的 Z 間隙" +msgid "" +"Z gap between the object and the support bottom. " +"If Support Top Z Distance is 0 and the bottom has interface layers, this value " +"is ignored and the support is printed in direct contact with the object (no gap)." +msgstr "" +"模型與支撐底部之間的Z間隙。" +"若支撐頂部Z距離為0且底部有介面層,則忽略此值,支撐與模型直接接觸列印(無間隙)。" msgid "Support/raft base" msgstr "支撐/筏層主體" diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index f1acad9ba7..cb2e6c7c1a 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -322,6 +322,7 @@ protected: ExPolygon *area; int type; int interface_id = 0; + bool interface_as_base = false; coordf_t dist_to_top; // mm dist to top bool need_infill = false; bool need_extra_wall = false; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0115ae54aa..07cfb8863a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4854,7 +4854,9 @@ void PrintConfigDef::init_fff_params() def = this->add("raft_contact_distance", coFloat); def->label = L("Raft contact Z distance"); def->category = L("Support"); - def->tooltip = L("Z gap between object and raft. Ignored for soluble interface."); + def->tooltip = L("Z gap between raft and object. " + "If Support Top Z Distance is 0, this value is ignored and " + "the object is printed in direct contact with the raft (no gap)."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = 0; def->mode = comAdvanced; @@ -5839,7 +5841,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Top Z distance"); def->min = 0; def->category = L("Support"); - def->tooltip = L("The Z gap between the top support interface and object."); + def->tooltip = L("Z gap between the support's top and object."); def->sidetext = L("mm"); // millimeters, CIS languages need translation // def->min = 0; #if 0 @@ -5856,7 +5858,9 @@ void PrintConfigDef::init_fff_params() def = this->add("support_bottom_z_distance", coFloat); def->label = L("Bottom Z distance"); def->category = L("Support"); - def->tooltip = L("The Z gap between the bottom support interface and object."); + def->tooltip = L("Z gap between the object and the support bottom. " + "If Support Top Z Distance is 0 and the bottom has interface layers, this value " + "is ignored and the support is printed in direct contact with the object (no gap)."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = 0; def->mode = comAdvanced; diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index aa24b1074d..c8c37a5a79 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -60,14 +60,15 @@ coordf_t Slicing::max_layer_height_from_nozzle(const DynamicPrintConfig &print_c } SlicingParameters SlicingParameters::create_from_config( - const PrintConfig &print_config, - const PrintObjectConfig &object_config, - coordf_t object_height, - const std::vector &object_extruders, - const Vec3d &object_shrinkage_compensation) + const PrintConfig &print_config, + const PrintObjectConfig &object_config, + coordf_t object_height, + const std::vector &object_extruders, + const Vec3d &object_shrinkage_compensation) { coordf_t initial_layer_print_height = (print_config.initial_layer_print_height.value <= 0) ? object_config.layer_height.value : print_config.initial_layer_print_height.value; + // If object_config.support_filament == 0 resp. object_config.support_interface_filament == 0, // print_config.nozzle_diameter.get_at(size_t(-1)) returns the 0th nozzle diameter, // which is consistent with the requirement that if support_filament == 0 resp. support_interface_filament == 0, @@ -75,19 +76,47 @@ SlicingParameters SlicingParameters::create_from_config( // In that case all the nozzles have to be of the same diameter. coordf_t support_material_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_filament.value - 1); coordf_t support_material_interface_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_interface_filament.value - 1); - bool soluble_interface = object_config.support_top_z_distance.value == 0.; + + // ORCA: store Z distance + const coordf_t support_top_z_gap = object_config.support_top_z_distance.value; + const coordf_t support_bottom_z_gap = object_config.support_bottom_z_distance.value; + const coordf_t raft_z_gap = object_config.raft_contact_distance.value; + + + /* -------------------------------------------------- */ + /* ORCA: Zero-gap interface detection (asymmetric) */ + /* -------------------------------------------------- */ + + const bool zero_topZ_contact = + support_top_z_gap == 0.0; + + const bool zero_gap_interface_top = + object_config.support_interface_top_layers.value > 0 && // Has some top interface layers + zero_topZ_contact; + + const bool zero_gap_interface_bottom = + (object_config.support_interface_bottom_layers.value < 0 // Negative value means "use same as top" + ? object_config.support_interface_top_layers.value + : object_config.support_interface_bottom_layers.value) > 0 && // Has some bottom interface layers + (support_bottom_z_gap == 0.0 || zero_topZ_contact); + + const bool zero_gap_interface_raft = + raft_z_gap == 0.0 || zero_topZ_contact; SlicingParameters params; - params.layer_height = object_config.layer_height.value; - params.first_print_layer_height = initial_layer_print_height; - params.first_object_layer_height = initial_layer_print_height; - params.object_print_z_min = 0.; + + params.layer_height = object_config.layer_height.value; + params.first_print_layer_height = initial_layer_print_height; + params.first_object_layer_height = initial_layer_print_height; + params.object_print_z_min = 0.0; // Orca: XYZ filament compensation - params.object_print_z_max = object_height * object_shrinkage_compensation.z(); + params.object_print_z_max = object_height * object_shrinkage_compensation.z(); params.object_print_z_uncompensated_max = object_height; - params.object_shrinkage_compensation_z = object_shrinkage_compensation.z(); - params.base_raft_layers = object_config.raft_layers.value; - params.soluble_interface = soluble_interface; + params.object_shrinkage_compensation_z = object_shrinkage_compensation.z(); + params.base_raft_layers = object_config.raft_layers.value; + params.zero_gap_interface_top = zero_gap_interface_top; + params.zero_gap_interface_bottom = zero_gap_interface_bottom; + params.zero_gap_interface_raft = zero_gap_interface_raft; // Miniumum/maximum of the minimum layer height over all extruders. params.min_layer_height = MIN_LAYER_HEIGHT; @@ -102,6 +131,7 @@ SlicingParameters SlicingParameters::create_from_config( max_layer_height_from_nozzle(print_config, object_config.support_interface_filament)); params.max_suport_layer_height = params.max_layer_height; } + if (object_extruders.empty()) { params.min_layer_height = std::max(params.min_layer_height, min_layer_height_from_nozzle(print_config, 0)); params.max_layer_height = std::min(params.max_layer_height, max_layer_height_from_nozzle(print_config, 0)); @@ -111,24 +141,58 @@ SlicingParameters SlicingParameters::create_from_config( params.max_layer_height = std::min(params.max_layer_height, max_layer_height_from_nozzle(print_config, extruder_id)); } } + params.min_layer_height = std::min(params.min_layer_height, params.layer_height); params.max_layer_height = std::max(params.max_layer_height, params.layer_height); - if (! soluble_interface) { - params.gap_raft_object = object_config.raft_contact_distance.value; - //BBS - params.gap_object_support = object_config.support_bottom_z_distance.value; - params.gap_support_object = object_config.support_top_z_distance.value; + /* -------------------------------------------------- */ + /* ORCA: Gap assignment */ + /* -------------------------------------------------- */ + // ORCA: Raft contact (raft -> object) + if (zero_gap_interface_raft) { + params.gap_raft_object = 0.0; + } else { + params.gap_raft_object = raft_z_gap; if (!print_config.independent_support_layer_height) { - params.gap_raft_object = std::round(params.gap_raft_object / object_config.layer_height + EPSILON) * object_config.layer_height; - params.gap_object_support = std::round(params.gap_object_support / object_config.layer_height + EPSILON) * object_config.layer_height; - params.gap_support_object = std::round(params.gap_support_object / object_config.layer_height + EPSILON) * object_config.layer_height; + params.gap_raft_object = + std::round(params.gap_raft_object / object_config.layer_height + EPSILON) + * object_config.layer_height; } } + // ORCA: BOTTOM contact (object -> support) + if (zero_gap_interface_bottom) { + params.gap_object_support = 0.0; + } else { + params.gap_object_support = support_bottom_z_gap; + + if (!print_config.independent_support_layer_height) { + params.gap_object_support = + std::round(params.gap_object_support / object_config.layer_height + EPSILON) + * object_config.layer_height; + } + } + + // ORCA: TOP contact (support -> object) + if (zero_gap_interface_top) { + params.gap_support_object = 0.0; + } else { + params.gap_support_object = support_top_z_gap; + + if (!print_config.independent_support_layer_height) { + params.gap_support_object = + std::round(params.gap_support_object / object_config.layer_height + EPSILON) + * object_config.layer_height; + } + } + + /* -------------------------------------------------- */ + /* Raft logic */ + /* -------------------------------------------------- */ + if (params.base_raft_layers > 0) { - params.interface_raft_layers = (params.base_raft_layers + 1) / 2; + params.interface_raft_layers = (params.base_raft_layers + 1) / 2; params.base_raft_layers -= params.interface_raft_layers; // Use as large as possible layer height for the intermediate raft layers. params.base_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_extruder_dmr); @@ -141,11 +205,11 @@ SlicingParameters SlicingParameters::create_from_config( if (params.has_raft()) { // Raise first object layer Z by the thickness of the raft itself plus the extra distance required by the support material logic. //FIXME The last raft layer is the contact layer, which shall be printed with a bridging flow for ease of separation. Currently it is not the case. - if (params.raft_layers() == 1) { + if (params.raft_layers() == 1) { // There is only the contact layer. params.contact_raft_layer_height = initial_layer_print_height; params.raft_contact_top_z = initial_layer_print_height; - } else { + } else { assert(params.base_raft_layers > 0); assert(params.interface_raft_layers > 0); // Number of the base raft layers is decreased by the first layer. @@ -153,7 +217,8 @@ SlicingParameters SlicingParameters::create_from_config( // Number of the interface raft layers is decreased by the contact layer. params.raft_interface_top_z = params.raft_base_top_z + coordf_t(params.interface_raft_layers - 1) * params.interface_raft_layer_height; params.raft_contact_top_z = params.raft_interface_top_z + params.contact_raft_layer_height; - } + } + coordf_t print_z = params.raft_contact_top_z + params.gap_raft_object; params.object_print_z_min = print_z; params.object_print_z_max += print_z; diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index a7b21a140d..f735ec5518 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -84,9 +84,10 @@ struct SlicingParameters // If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow. bool first_object_layer_bridging { false }; - // Soluble interface? (PLA soluble in water, HIPS soluble in lemonen) - // otherwise the interface must be broken off. - bool soluble_interface { false }; + // Zero-gap interface flags for top / bottom / raft contact. + bool zero_gap_interface_top { false }; + bool zero_gap_interface_bottom { false }; + bool zero_gap_interface_raft { false }; // Gap when placing object over raft. coordf_t gap_raft_object { 0 }; // Gap when placing support over object. @@ -100,7 +101,7 @@ struct SlicingParameters coordf_t raft_base_top_z { 0 }; coordf_t raft_interface_top_z { 0 }; coordf_t raft_contact_top_z { 0 }; - // In case of a soluble interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer. + // In case of a zero-gap raft interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer. coordf_t object_print_z_min { 0 }; // This value of maximum print Z is scaled by shrinkage compensation in the Z-axis. coordf_t object_print_z_max { 0 }; @@ -133,7 +134,9 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters // BBS: following are not required for equal layer height. // Since the z-gap diff may be multiple of layer height. #if 0 - sp1.soluble_interface == sp2.soluble_interface && + sp1.zero_gap_interface_top == sp2.zero_gap_interface_top && + sp1.zero_gap_interface_bottom == sp2.zero_gap_interface_bottom && + sp1.zero_gap_interface_raft == sp2.zero_gap_interface_raft && sp1.gap_raft_object == sp2.gap_raft_object && sp1.gap_object_support == sp2.gap_object_support && sp1.gap_support_object == sp2.gap_support_object && diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 75e04ad4aa..67809df075 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "SupportCommon.hpp" @@ -69,22 +70,30 @@ std::pair generate_interfa if (support_params.has_base_interfaces()) base_interface_layers.assign(intermediate_layers.size(), nullptr); const auto smoothing_distance = support_params.support_material_interface_flow.scaled_spacing() * 1.5; - const auto minimum_island_radius = support_params.support_material_interface_flow.scaled_spacing() / support_params.interface_density; + // ORCA: use top/bottom interface densities for smoothing. + const auto minimum_island_radius_top = support_params.support_material_interface_flow.scaled_spacing() / support_params.top_interface_density; + const auto minimum_island_radius_bottom = support_params.support_material_interface_flow.scaled_spacing() / support_params.bottom_interface_density; const auto closing_distance = smoothing_distance; // scaled(config.support_material_closing_radius.value); // Insert a new layer into base_interface_layers, if intersection with base exists. - auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius]( + // ORCA: regularize top and bottom interfaces with separate minimum island radii. + auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius_top, minimum_island_radius_bottom]( SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, SupportGeneratorLayer *top_interface_layer, const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* { bool has_top_interface = top_interface_layer && ! top_interface_layer->polygons.empty(); assert(! bottom.empty() || ! top.empty() || has_top_interface); - // Merge top into bottom, unite them with a safety offset. - append(bottom, std::move(top)); - // Merge top / bottom interfaces. For snug supports, merge using closing distance and regularize (close concave corners). - bottom = intersection( - smooth_supports ? - smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) : - union_safety_offset(std::move(bottom)), - intermediate_layer.polygons); + // ORCA: regularize interfaces using the top/bottom radii. + auto regularize = [&](Polygons polys, coordf_t minimum_island_radius) -> Polygons { + if (polys.empty()) + return polys; + return smooth_supports ? + smooth_outward(closing(std::move(polys), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) : + union_safety_offset(std::move(polys)); + }; + // ORCA: apply independent smoothing to bottom vs top. + Polygons bottom_polys = regularize(std::move(bottom), minimum_island_radius_bottom); + Polygons top_polys = regularize(std::move(top), minimum_island_radius_top); + append(bottom_polys, std::move(top_polys)); + bottom = intersection(std::move(bottom_polys), intermediate_layer.polygons); if (has_top_interface) { // Don't trim the precomputed Organic supports top interface with base layer // as the precomputed top interface likely expands over multiple tree tips. @@ -1365,7 +1374,8 @@ SupportGeneratorLayersPtr generate_support_layers( SupportGeneratorLayer &layer = *layers_sorted[u]; if (! layer.polygons.empty()) { empty = false; - num_interfaces += one_of(layer.layer_type, support_types_interface); + const bool is_base_interface = std::find(base_interface_layers.begin(), base_interface_layers.end(), &layer) != base_interface_layers.end(); + num_interfaces += one_of(layer.layer_type, support_types_interface) || is_base_interface; if (layer.layer_type == SupporLayerType::TopContact) { ++ num_top_contacts; assert(num_top_contacts <= 1); @@ -1562,7 +1572,7 @@ void generate_support_toolpaths( auto filler_raft_contact = filler_raft_contact_ptr ? filler_raft_contact_ptr.get() : filler_interface.get(); // Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer). auto filler_base_interface = std::unique_ptr(base_interface_layers.empty() ? nullptr : - Fill::new_from_type(support_params.interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase)); + Fill::new_from_type(support_params.top_interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase)); auto filler_support = std::unique_ptr(Fill::new_from_type(support_params.base_fill_pattern)); filler_interface->set_bounding_box(bbox_object); if (filler_first_layer_ptr) @@ -1610,6 +1620,8 @@ void generate_support_toolpaths( // This layer is a raft contact layer. Any contact polygons at this layer are raft contacts. bool raft_layer = slicing_params.interface_raft_layers && top_contact_layer.layer && is_approx(top_contact_layer.layer->print_z, slicing_params.raft_contact_top_z); + // ORCA: Organic tree uses projected contacts to build the interface stack; avoid extra bottom-contact extrusion. + const bool organic_tree = support_params.support_style == SupportMaterialStyle::smsTreeOrganic; if (config.support_interface_top_layers == 0) { // If no top interface layers were requested, we treat the contact layer exactly as a generic base layer. // Don't merge the raft contact layer though. @@ -1638,10 +1650,34 @@ void generate_support_toolpaths( base_layer.merge(std::move(bottom_contact_layer)); else if (base_layer.empty() && ! bottom_contact_layer.empty() && ! bottom_contact_layer.layer->bridging) base_layer = std::move(bottom_contact_layer); - } else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer) + } else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer) { top_contact_layer.merge(std::move(bottom_contact_layer)); - else if (bottom_contact_layer.could_merge(interface_layer)) + } else if (bottom_contact_layer.could_merge(interface_layer) && ! organic_tree) { bottom_contact_layer.merge(std::move(interface_layer)); + } + + // Orca: For organic trees the support-material regions are generated from + // expanded wall polygons. With zero top Z gap and separate interface material, + // that expansion can overlap same-layer interface-material regions, so trim + // the support-material regions from those interface footprints here. + if (organic_tree && support_params.zero_gap_interface_top && !support_params.can_merge_support_regions && + (!base_layer.empty() || !base_interface_layer.empty())) { + Polygons interface_polygons; + if (!top_contact_layer.empty()) + polygons_append(interface_polygons, top_contact_layer.polygons_to_extrude()); + if (!interface_layer.empty()) + polygons_append(interface_polygons, interface_layer.polygons_to_extrude()); + if (!interface_polygons.empty()) { + const coord_t trim_margin = std::max( + support_params.support_material_flow.scaled_width(), + support_params.support_material_interface_flow.scaled_width()); + Polygons interface_keepout = offset(interface_polygons, trim_margin); + if (!base_layer.empty()) + base_layer.set_polygons_to_extrude(diff(base_layer.polygons_to_extrude(), interface_keepout)); + if (!base_interface_layer.empty()) + base_interface_layer.set_polygons_to_extrude(diff(base_interface_layer.polygons_to_extrude(), interface_keepout)); + } + } #if 0 if ( ! interface_layer.empty() && ! base_layer.empty()) { @@ -1661,6 +1697,9 @@ void generate_support_toolpaths( if (! layer_ex.empty() && ! layer_ex.polygons_to_extrude().empty()) { bool interface_as_base = interface_layer_type == InterfaceLayerType::InterfaceAsBase; bool raft_contact = interface_layer_type == InterfaceLayerType::RaftContact; + // ORCA: detect bottom interface layers for density selection. + bool bottom_interface = interface_layer_type == InterfaceLayerType::BottomContact || + (interface_layer_type == InterfaceLayerType::Interface && layer_ex.layer->layer_type == SupporLayerType::BottomInterface); //FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b) auto *filler = raft_contact ? filler_raft_contact : filler_interface.get(); @@ -1676,7 +1715,10 @@ void generate_support_toolpaths( raft_contact ? support_params.raft_interface_angle(support_layer.interface_id()) : support_interface_angle; - double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density; + // ORCA: pick density based on interface type. + double density = raft_contact ? support_params.raft_interface_density : + interface_as_base ? support_params.support_density : + bottom_interface ? support_params.bottom_interface_density : support_params.top_interface_density; filler->spacing = raft_contact ? support_params.raft_interface_flow.spacing() : interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); @@ -1694,9 +1736,9 @@ void generate_support_toolpaths( const bool top_interfaces = config.support_interface_top_layers.value != 0; const bool bottom_interfaces = top_interfaces && config.support_interface_bottom_layers != 0; extrude_interface(top_contact_layer, raft_layer ? InterfaceLayerType::RaftContact : top_interfaces ? InterfaceLayerType::TopContact : InterfaceLayerType::InterfaceAsBase); - extrude_interface(bottom_contact_layer, bottom_interfaces ? InterfaceLayerType::BottomContact : InterfaceLayerType::InterfaceAsBase); + if (!organic_tree) + extrude_interface(bottom_contact_layer, bottom_interfaces ? InterfaceLayerType::BottomContact : InterfaceLayerType::InterfaceAsBase); extrude_interface(interface_layer, top_interfaces ? InterfaceLayerType::Interface : InterfaceLayerType::InterfaceAsBase); - // Base interface layers under soluble interfaces if ( ! base_interface_layer.empty() && ! base_interface_layer.polygons_to_extrude().empty()) { Fill *filler = filler_base_interface.get(); @@ -1706,7 +1748,7 @@ void generate_support_toolpaths( Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height)); filler->angle = support_interface_angle; filler->spacing = support_params.support_material_interface_flow.spacing(); - filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density)); + filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.top_interface_density)); fill_expolygons_generate_paths( // Destination base_interface_layer.extrusions, @@ -1714,7 +1756,7 @@ void generate_support_toolpaths( // Regions to fill union_safety_offset_ex(base_interface_layer.polygons_to_extrude()), // Filler and its parameters - filler, float(support_params.interface_density), + filler, float(support_params.top_interface_density), // Extrusion parameters ExtrusionRole::erSupportMaterial, interface_flow); } diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index 61484730ea..da26be6b84 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -1739,7 +1739,7 @@ static inline std::pair new_cont print_z = slicing_params.raft_contact_top_z; bottom_z = slicing_params.raft_interface_top_z; height = slicing_params.contact_raft_layer_height; - } else if (slicing_params.soluble_interface) { + } else if (slicing_params.zero_gap_interface_top) { // Align the contact surface height with a layer immediately below the supported layer. // Interface layer will be synchronized with the object. print_z = layer.bottom_z(); @@ -1862,7 +1862,7 @@ static inline void fill_contact_layer( #endif // SLIC3R_DEBUG )); // 2) infill polygons, expand them by half the extrusion width + a tiny bit of extra. - bool reduce_interfaces = object_config.support_style.value != smsSnug && layer_id > 0 && !slicing_params.soluble_interface; + bool reduce_interfaces = object_config.support_style.value != smsSnug && layer_id > 0 && !slicing_params.zero_gap_interface_top; if (reduce_interfaces) { // Reduce the amount of dense interfaces: Do not generate dense interfaces below overhangs with 60% overhang of the extrusions. Polygons dense_interface_polygons = diff(overhang_polygons, lower_layer_polygons_for_dense_interface()); @@ -2421,12 +2421,12 @@ static inline SupportGeneratorLayer* detect_bottom_contacts( Layer* upper_layer = layer.upper_layer; if (object.print()->config().independent_support_layer_height) { // If the layer is extruded with no bridging flow, support just the normal extrusions. - layer_new.height = slicing_params.soluble_interface ? + layer_new.height = slicing_params.zero_gap_interface_bottom ? // Align the interface layer with the object's layer height. upper_layer->height : // Place a bridge flow interface layer or the normal flow interface layer over the top surface. support_params.support_material_bottom_interface_flow.height(); - layer_new.print_z = slicing_params.soluble_interface ? upper_layer->print_z : + layer_new.print_z = slicing_params.zero_gap_interface_bottom ? upper_layer->print_z : layer.print_z + layer_new.height + slicing_params.gap_object_support; } else { @@ -2436,11 +2436,11 @@ static inline SupportGeneratorLayer* detect_bottom_contacts( } layer_new.bottom_z = layer.print_z; layer_new.idx_object_layer_below = layer_id; - layer_new.bridging = !slicing_params.soluble_interface && object.config().thick_bridges; + layer_new.bridging = !slicing_params.zero_gap_interface_bottom && object.config().thick_bridges; //FIXME how much to inflate the bottom surface, as it is being extruded with a bridging flow? The following line uses a normal flow. layer_new.polygons = expand(touching, float(support_params.support_material_flow.scaled_width()), SUPPORT_SURFACES_OFFSET_PARAMETERS); - if (! slicing_params.soluble_interface) { + if (!slicing_params.zero_gap_interface_bottom) { // Walk the top surfaces, snap the top of the new bottom surface to the closest top of the top surface, // so there will be no support surfaces generated with thickness lower than m_support_layer_height_min. for (size_t top_idx = size_t(std::max(0, contact_idx)); @@ -2909,7 +2909,7 @@ SupportGeneratorLayersPtr PrintObjectSupportMaterial::raft_and_intermediate_supp // Continue printing the other layers up to extr2z. step = dist / coordf_t(n_layers_extra); } - if (! m_slicing_params.soluble_interface && extr2->layer_type == SupporLayerType::TopContact) { + if (!m_slicing_params.zero_gap_interface_top && extr2->layer_type == SupporLayerType::TopContact) { // This is a top interface layer, which does not have a height assigned yet. Do it now. assert(extr2->height == 0.); assert(extr1z > m_slicing_params.first_print_layer_height - EPSILON); @@ -3170,7 +3170,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); } } - if (! m_slicing_params.soluble_interface && m_object_config->thick_bridges) { + if (!m_slicing_params.zero_gap_interface_top && m_object_config->thick_bridges) { // Collect all bottom surfaces, which will be extruded with a bridging flow. for (; i < object.layers().size(); ++ i) { const Layer &object_layer = *object.layers()[i]; diff --git a/src/libslic3r/Support/SupportMaterial.hpp b/src/libslic3r/Support/SupportMaterial.hpp index e489c2374a..50b8256c4a 100644 --- a/src/libslic3r/Support/SupportMaterial.hpp +++ b/src/libslic3r/Support/SupportMaterial.hpp @@ -28,7 +28,7 @@ public: bool has_support() const { return m_object_config->enable_support.value || m_object_config->enforce_support_layers; } bool build_plate_only() const { return this->has_support() && m_object_config->support_on_build_plate_only.value; } // BBS - bool synchronize_layers() const { return /*m_slicing_params.soluble_interface && */!m_print_config->independent_support_layer_height.value; } + bool synchronize_layers() const { return /*m_slicing_params.zero_gap_interface_top && */!m_print_config->independent_support_layer_height.value; } bool has_contact_loops() const { return m_object_config->support_interface_loop_pattern.value; } // Generate support material for the object. diff --git a/src/libslic3r/Support/SupportParameters.hpp b/src/libslic3r/Support/SupportParameters.hpp index 655ee0d806..c1468eb5f9 100644 --- a/src/libslic3r/Support/SupportParameters.hpp +++ b/src/libslic3r/Support/SupportParameters.hpp @@ -14,14 +14,15 @@ struct SupportParameters { const PrintObjectConfig& object_config = object.config(); const SlicingParameters& slicing_params = object.slicing_parameters(); - this->soluble_interface = slicing_params.soluble_interface; - this->soluble_interface_non_soluble_base = - // Zero z-gap between the overhangs and the support interface. - slicing_params.soluble_interface && - // Interface extruder soluble. - object_config.support_interface_filament.value > 0 && print_config.filament_soluble.get_at(object_config.support_interface_filament.value - 1) && - // Base extruder: Either "print with active extruder" not soluble. - (object_config.support_filament.value == 0 || ! print_config.filament_soluble.get_at(object_config.support_filament.value - 1)); + this->zero_gap_interface_top = slicing_params.zero_gap_interface_top; + this->zero_gap_interface_bottom = slicing_params.zero_gap_interface_bottom; + const bool soluble_interface_non_soluble_base = + // Interface extruder soluble. + object_config.support_interface_filament.value > 0 && print_config.filament_soluble.get_at(object_config.support_interface_filament.value - 1) && + // Base extruder: Either "print with active extruder" not soluble. + (object_config.support_filament.value == 0 || ! print_config.filament_soluble.get_at(object_config.support_filament.value - 1)); + const bool non_soluble_base_top = this->zero_gap_interface_top && soluble_interface_non_soluble_base; + const bool non_soluble_base_bottom = this->zero_gap_interface_bottom && soluble_interface_non_soluble_base; { this->num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value); @@ -29,19 +30,25 @@ struct SupportParameters { num_top_interface_layers : object_config.support_interface_bottom_layers; this->has_top_contacts = num_top_interface_layers > 0; this->has_bottom_contacts = num_bottom_interface_layers > 0; - if (this->soluble_interface_non_soluble_base) { - // Try to support soluble dense interfaces with non-soluble dense interfaces. - this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2)); - this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2)); - } else { - // BBS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion - // Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if - // support_filament==0 - bool differnt_support_interface_filament = object_config.support_interface_filament != 0 && - object_config.support_interface_filament != object_config.support_filament; - this->num_top_base_interface_layers = differnt_support_interface_filament ? 1 : 0; - this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0; - } + // BBS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion + // Note: support materials (such as Supp.W) can't be used as support base now, so support interface and base are still using different filaments even if + // support_filament==0 + bool different_support_interface_filament = object_config.support_interface_filament != 0 && + object_config.support_interface_filament != object_config.support_filament; + + if (non_soluble_base_top) { // ORCA: Try to support soluble dense interfaces with non-soluble dense interfaces. + this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2)); + } else { + this->num_top_base_interface_layers = + (different_support_interface_filament && this->zero_gap_interface_top) ? 1 : 0; + } + + if (non_soluble_base_bottom) { // ORCA: Try to support soluble dense interfaces with non-soluble dense interfaces. + this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2)); + } else { + this->num_bottom_base_interface_layers = + (different_support_interface_filament && this->zero_gap_interface_bottom) ? 1 : 0; + } } this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height)); this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height)); @@ -78,7 +85,7 @@ struct SupportParameters { this->gap_xy_first_layer = object_config.support_object_first_layer_gap.value; bridge_flow_ratio /= object.num_printing_regions(); - this->support_material_bottom_interface_flow = slicing_params.soluble_interface || !object_config.thick_bridges ? + this->support_material_bottom_interface_flow = this->zero_gap_interface_bottom || !object_config.thick_bridges ? this->support_material_interface_flow.with_flow_ratio(bridge_flow_ratio) : Flow::bridging_flow(bridge_flow_ratio * this->support_material_interface_flow.nozzle_diameter(), this->support_material_interface_flow.nozzle_diameter()); @@ -95,18 +102,21 @@ struct SupportParameters { this->base_angle = Geometry::deg2rad(float(object_config.support_angle.value)); this->interface_angle = Geometry::deg2rad(float(object_config.support_angle.value + 90.)); - // Orca: Force solid support interface when using support ironing - this->interface_spacing = (this->ironing ? 0 : object_config.support_interface_spacing.value) + this->support_material_interface_flow.spacing(); - this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->interface_spacing); - // Orca: Force solid support interface when using support ironing + // ORCA: split top/bottom interface spacing and density, and force solid top when ironing. + this->top_interface_spacing = (this->ironing ? 0 : object_config.support_interface_spacing.value) + this->support_material_interface_flow.spacing(); + this->top_interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->top_interface_spacing); + // ORCA: bottom interface spacing/density separated from top settings. + this->bottom_interface_spacing = object_config.support_bottom_interface_spacing.value + this->support_material_interface_flow.spacing(); + this->bottom_interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->bottom_interface_spacing); + // ORCA: force solid raft interface when ironing (top spacing). double raft_interface_spacing = (this->ironing ? 0 : object_config.support_interface_spacing.value) + this->raft_interface_flow.spacing(); this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing); this->support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing(); this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing); if (object_config.support_interface_top_layers.value == 0) { // No interface layers allowed, print everything with the base support pattern. - this->interface_spacing = this->support_spacing; - this->interface_density = this->support_density; + this->top_interface_spacing = this->support_spacing; + this->top_interface_density = this->support_density; } SupportMaterialPattern support_pattern = object_config.support_base_pattern; @@ -114,7 +124,7 @@ struct SupportParameters { this->base_fill_pattern = support_pattern == smpHoneycomb ? ipHoneycomb : this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase; - this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase); + this->interface_fill_pattern = (this->top_interface_density > 0.95 ? ipRectilinear : ipSupportBase); this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase; if (object_config.support_interface_pattern == smipGrid) this->contact_fill_pattern = ipGrid; @@ -122,10 +132,10 @@ struct SupportParameters { this->contact_fill_pattern = ipRectilinear; else this->contact_fill_pattern = - (object_config.support_interface_pattern == smipAuto && slicing_params.soluble_interface) || + (object_config.support_interface_pattern == smipAuto && this->zero_gap_interface_top) || object_config.support_interface_pattern == smipConcentric ? ipConcentric : - (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase); + (this->top_interface_density > 0.95 ? ipRectilinear : ipSupportBase); this->raft_angle_1st_layer = 0.f; this->raft_angle_base = 0.f; @@ -186,10 +196,9 @@ struct SupportParameters { } } } - // Both top / bottom contacts and interfaces are soluble. - bool soluble_interface; - // Support contact & interface are soluble, but support base is non-soluble. - bool soluble_interface_non_soluble_base; + // Zero-gap interface flags for top / bottom contact. + bool zero_gap_interface_top; + bool zero_gap_interface_bottom; // Is there at least a top contact layer extruded above support base? bool has_top_contacts; @@ -199,9 +208,9 @@ struct SupportParameters { size_t num_top_interface_layers; // Number of bottom interface layers without counting the contact layer. size_t num_bottom_interface_layers; - // Number of top base interface layers. Zero if not soluble_interface_non_soluble_base. + // Number of top base interface layers. size_t num_top_base_interface_layers; - // Number of bottom base interface layers. Zero if not soluble_interface_non_soluble_base. + // Number of bottom base interface layers. size_t num_bottom_base_interface_layers; bool has_contacts() const { return this->has_top_contacts || this->has_bottom_contacts; } @@ -233,10 +242,13 @@ struct SupportParameters { float base_angle; float interface_angle; - coordf_t interface_spacing; + coordf_t top_interface_spacing; + coordf_t bottom_interface_spacing; coordf_t support_expansion=0; - // Density of the top / bottom interface and contact layers. - coordf_t interface_density; + // Density of the top interface and contact layers. + coordf_t top_interface_density; + // Density of the bottom interface and contact layers. + coordf_t bottom_interface_density; // Density of the raft interface and contact layers. coordf_t raft_interface_density; coordf_t support_spacing; diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index e6ed4acc96..215fc12c8c 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -25,6 +25,7 @@ #include #include +#include #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 @@ -73,6 +74,32 @@ inline Point normal(Point pt, double scale) return pt * (scale / length); } +// ORCA: +// Collect all polygons of a given SurfaceType from all regions of a layer. +// Used for top-contact probing across region/modifier boundaries. +static Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_type) +{ + size_t n_polygons_new = 0; + + for (const LayerRegion *region : layer.regions()) { + for (const Surface &surface : region->slices.surfaces) { + if (surface.surface_type == surface_type) + n_polygons_new += surface.expolygon.holes.size() + 1; + } + } + + Polygons out; + out.reserve(n_polygons_new); + + for (const LayerRegion *region : layer.regions()) { + for (const Surface &surface : region->slices.surfaces) { + if (surface.surface_type == surface_type) + polygons_append(out, surface.expolygon); + } + } + + return out; +} enum TreeSupportStage { STAGE_DETECT_OVERHANGS, @@ -1416,7 +1443,7 @@ void TreeSupport::generate_toolpaths() Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); Fill* filler_interface = Fill::new_from_type(ipRectilinear); - filler_interface->angle = PI / 2; // interface should be perpendicular to base + filler_interface->angle = M_PI_2; // interface should be perpendicular to base filler_interface->spacing = support_flow.spacing(); FillParams fill_params; @@ -1436,7 +1463,7 @@ void TreeSupport::generate_toolpaths() SupportLayer *ts_layer = m_object->get_support_layer(layer_nr); Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); Fill* filler_raft = Fill::new_from_type(ipRectilinear); - filler_raft->angle = PI / 2; + filler_raft->angle = M_PI_2; filler_raft->spacing = support_flow.spacing(); for (auto& poly : first_non_raft_base) make_perimeter_and_infill(ts_layer->support_fills.entities, poly, std::min(size_t(1), wall_count), support_flow, erSupportMaterial, filler_raft, interface_density, false); @@ -1446,13 +1473,8 @@ void TreeSupport::generate_toolpaths() return; BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.))); - - std::shared_ptr filler_interface = std::shared_ptr(Fill::new_from_type(m_support_params.contact_fill_pattern)); - std::shared_ptr filler_Roof1stLayer = std::shared_ptr(Fill::new_from_type(ipRectilinear)); - filler_interface->set_bounding_box(bbox_object); - filler_Roof1stLayer->set_bounding_box(bbox_object); - filler_interface->angle = Geometry::deg2rad(object_config.support_angle.value + 90.); - filler_Roof1stLayer->angle = Geometry::deg2rad(object_config.support_angle.value + 90.); + // ORCA: base angle used for explicit interlaced interface orientation. + const float base_support_angle = Geometry::deg2rad(object_config.support_angle.value); // generate tree support tool paths tbb::parallel_for( @@ -1471,17 +1493,28 @@ void TreeSupport::generate_toolpaths() coordf_t support_spacing = object_config.support_base_pattern_spacing.value + support_flow.spacing(); coordf_t support_density = std::min(1., support_flow.spacing() / support_spacing); ts_layer->support_fills.no_sort = false; + // ORCA: per-layer Fill instances to avoid shared-state races during interlaced interfaces. + std::shared_ptr filler_interface = std::shared_ptr(Fill::new_from_type(m_support_params.contact_fill_pattern)); + std::shared_ptr filler_Roof1stLayer = std::shared_ptr(Fill::new_from_type(ipRectilinear)); + filler_interface->set_bounding_box(bbox_object); + filler_Roof1stLayer->set_bounding_box(bbox_object); for (auto& area_group : ts_layer->area_groups) { ExPolygon& poly = *area_group.area; ExPolygons polys; FillParams fill_params; + // ORCA: reset interface Fill state per area group to keep angles deterministic. + filler_interface->fixed_angle = false; + filler_interface->layer_id = size_t(-1); + filler_interface->angle = base_support_angle + M_PI_2; // default interface angle is perpendicular to support angle if (area_group.type != SupportLayer::BaseType) { // interface if (layer_id == 0) { Flow flow = m_raft_layers == 0 ? m_object->print()->brim_flow() : support_flow; + ExtrusionRole brim_role = (area_group.type == SupportLayer::RoofType && !area_group.interface_as_base) ? + erSupportMaterialInterface : erSupportMaterial; make_perimeter_and_inner_brim(ts_layer->support_fills.entities, poly, wall_count, flow, - area_group.type == SupportLayer::RoofType ? erSupportMaterialInterface : erSupportMaterial); + brim_role); polys = std::move(offset_ex(poly, -flow.scaled_spacing())); } else if (area_group.type == SupportLayer::Roof1stLayer) { polys = std::move(offset_ex(poly, 0.5*support_flow.scaled_width())); @@ -1494,12 +1527,18 @@ void TreeSupport::generate_toolpaths() } if (area_group.type == SupportLayer::Roof1stLayer) { // roof_1st_layer + // ORCA: Roof1stLayer may be printed with base material when it acts as a contact layer. + bool interface_as_base = area_group.interface_as_base; fill_params.density = interface_density; // Note: spacing means the separation between two lines as if they are tightly extruded filler_Roof1stLayer->spacing = interface_flow.spacing(); + filler_Roof1stLayer->angle = base_support_angle; + fill_params.dont_sort = true; + Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; + ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; // generate a perimeter first to support interface better ExtrusionEntityCollection* temp_support_fills = new ExtrusionEntityCollection(); - make_perimeter_and_infill(temp_support_fills->entities, poly, 1, interface_flow, erSupportMaterial, + make_perimeter_and_infill(temp_support_fills->entities, poly, 1, interface_base_flow, interface_role, filler_Roof1stLayer.get(), interface_density, false); temp_support_fills->no_sort = true; // make sure loops are first if (!temp_support_fills->entities.empty()) @@ -1508,23 +1547,49 @@ void TreeSupport::generate_toolpaths() delete temp_support_fills; } else if (area_group.type == SupportLayer::FloorType) { // floor_areas + bool interface_as_base = area_group.interface_as_base; fill_params.density = bottom_interface_density; filler_interface->spacing = interface_flow.spacing(); - fill_expolygons_generate_paths(ts_layer->support_fills.entities, polys, - filler_interface.get(), fill_params, erSupportMaterialInterface, interface_flow); - } else if (area_group.type == SupportLayer::RoofType) { - // roof_areas - fill_params.density = interface_density; - filler_interface->spacing = interface_flow.spacing(); + if (m_object_config->support_interface_pattern == smipGrid) { - filler_interface->angle = Geometry::deg2rad(object_config.support_angle.value); + filler_interface->angle = base_support_angle; fill_params.dont_sort = true; } - if (m_object_config->support_interface_pattern == smipRectilinearInterlaced) - filler_interface->layer_id = area_group.interface_id; - fill_expolygons_generate_paths(ts_layer->support_fills.entities, polys, filler_interface.get(), fill_params, erSupportMaterialInterface, - interface_flow); + if (m_object_config->support_interface_pattern == smipRectilinearInterlaced) { + // ORCA: explicit 0/90 alternation for rectilinear interlaced interfaces. + filler_interface->fixed_angle = true; + filler_interface->angle = base_support_angle + ((area_group.interface_id & 1) * M_PI_2); + fill_params.dont_sort = true; + } + + + Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; + ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; + fill_expolygons_generate_paths(ts_layer->support_fills.entities, polys, + filler_interface.get(), fill_params, interface_role, interface_base_flow); + } else if (area_group.type == SupportLayer::RoofType) { + // roof_areas + bool interface_as_base = area_group.interface_as_base; + fill_params.density = interface_density; + filler_interface->spacing = interface_flow.spacing(); + + if (m_object_config->support_interface_pattern == smipGrid) { + filler_interface->angle = base_support_angle; + fill_params.dont_sort = true; + } + + if (m_object_config->support_interface_pattern == smipRectilinearInterlaced) { + // ORCA: explicit 0/90 alternation for rectilinear interlaced interfaces. + filler_interface->fixed_angle = true; + filler_interface->angle = base_support_angle + ((area_group.interface_id & 1) * M_PI_2); + fill_params.dont_sort = true; + } + + Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; + ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; + fill_expolygons_generate_paths(ts_layer->support_fills.entities, polys, filler_interface.get(), fill_params, interface_role, + interface_base_flow); } else { // base_areas @@ -1890,7 +1955,7 @@ Polygons TreeSupport::get_trim_support_regions( polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); } } - if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) { + if (!m_slicing_params.zero_gap_interface_top && m_object_config->thick_bridges) { // Collect all bottom surfaces, which will be extruded with a bridging flow. for (; i < object.layers().size(); ++i) { const Layer& object_layer = *object.layers()[i]; @@ -1919,7 +1984,7 @@ void TreeSupport::draw_circles() const PrintObjectConfig &config = m_object->config(); const Print* print = m_object->print(); bool has_brim = print->has_brim(); - int bottom_gap_layers = round(m_slicing_params.gap_object_support / m_slicing_params.layer_height); + const coordf_t bottom_gap_height = m_slicing_params.gap_object_support; const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2; const coordf_t branch_radius_scaled = scale_(branch_radius); bool on_buildplate_only = m_object_config->support_on_build_plate_only.value; @@ -1935,7 +2000,7 @@ void TreeSupport::draw_circles() { double angle; if (SQUARE_SUPPORT) - angle = (double) i / CIRCLE_RESOLUTION * TAU + PI / 4.0 + nodes_angle; + angle = (double) i / CIRCLE_RESOLUTION * TAU + M_PI_4 + nodes_angle; else angle = (double) i / CIRCLE_RESOLUTION * TAU; branch_circle.append(Point(cos(angle) * branch_radius_scaled, sin(angle) * branch_radius_scaled)); @@ -1999,7 +2064,7 @@ void TreeSupport::draw_circles() coordf_t max_layers_above_base = 0; coordf_t max_layers_above_roof = 0; coordf_t max_layers_above_roof1 = 0; - int interface_id = 0; + bool floor_interface_as_base = false; bool has_circle_node = false; bool need_extra_wall = false; ExPolygons collision_sharp_tails; @@ -2033,6 +2098,8 @@ void TreeSupport::draw_circles() break; const SupportNode& node = *p_node; + // ORCA: Cap top interface height in mm based on per-node support layer height. + const coordf_t top_interface_height = coordf_t(top_interface_layers) * node.height; ExPolygons area; // Generate directly from overhang polygon if one of the following is true: // 1) node is a normal part of hybrid support @@ -2084,7 +2151,10 @@ void TreeSupport::draw_circles() // Merge the overhang into the roof area so tree tips can still produce // a continuous support interface. Suppressing this for build-plate-only // support drops the roof polygons entirely in valid tree branches. - if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !node.is_sharp_tail) { + // ORCA: Only keep top interface polygons that fully fit in the mm height cap. + if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && + (node.dist_mm_to_top - this->top_z_distance) < top_interface_height + EPSILON && + !node.is_sharp_tail) { ExPolygons overhang_expanded; if (node.overhang.contour.size() > 100 || node.overhang.holes.size()>1) overhang_expanded.emplace_back(node.overhang); @@ -2097,16 +2167,19 @@ void TreeSupport::draw_circles() if (obj_layer_nr>0 && node.distance_to_top < 0) append(roof_gap_areas, area); - else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 && node.is_sharp_tail==false) + // ORCA: Roof1stLayer must also fit inside the mm cap. + else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 && + (node.dist_mm_to_top - this->top_z_distance) < top_interface_height + EPSILON && node.is_sharp_tail==false) { append(roof_1st_layer, area); max_layers_above_roof1 = std::max(max_layers_above_roof1, node.dist_mm_to_top); } - else if (obj_layer_nr > 0 && node.support_roof_layers_below > 0 && node.is_sharp_tail == false) + // ORCA: Roof layers must also fit inside the mm cap. + else if (obj_layer_nr > 0 && node.support_roof_layers_below > 1 && + (node.dist_mm_to_top - this->top_z_distance) < top_interface_height + EPSILON && node.is_sharp_tail == false) { append(roof_areas, area); max_layers_above_roof = std::max(max_layers_above_roof, node.dist_mm_to_top); - interface_id = node.obj_layer_nr % top_interface_layers; } else { @@ -2135,7 +2208,6 @@ void TreeSupport::draw_circles() roof_1st_layer.clear(); max_layers_above_roof = std::max(max_layers_above_roof, max_layers_above_roof1); max_layers_above_roof1 = 0; - interface_id = obj_layer_nr % top_interface_layers; } ExPolygons roofs; append(roofs, roof_1st_layer); append(roofs, roof_areas);append(roofs, roof_gap_areas); @@ -2148,37 +2220,130 @@ void TreeSupport::draw_circles() for (auto &area : base_areas) { area.simplify(scale_(line_width / 2), &base_areas_simplified); } base_areas = std::move(base_areas_simplified); } - //Subtract support floors. We can only compute floor_areas here instead of with roof_areas, - // or we'll get much wider floor than necessary. - if (bottom_interface_layers + bottom_gap_layers > 0) + // ORCA: + // Bottom interface / bottom gap must be anchored to the *true* support-to-model contact surface. + // Do NOT window the contact search by gap or interface height. + // First find the real contact below, then enforce: + // - an empty gap below (contact_z + gap) + // - exactly N interface layers above that + if (!base_areas.empty() && !m_object_config->support_on_build_plate_only.value && + (bottom_gap_height > EPSILON || bottom_interface_layers > 0)) { - if (layer_nr >= bottom_interface_layers + bottom_gap_layers) - { - // find the lowest interface layer - // TODO the gap may not be exact when "independent support layer height" is enabled - size_t layer_nr_next = layer_nr - bottom_interface_layers; - size_t obj_layer_nr_next = m_ts_data->layer_heights[layer_nr_next].obj_layer_nr; - for (size_t i = 0; i <= bottom_gap_layers && i <= obj_layer_nr_next; i++) - { - const Layer *below_layer = m_object->get_layer(obj_layer_nr_next - i); - ExPolygons bottom_interface = intersection_ex(base_areas, below_layer->lslices); - floor_areas.insert(floor_areas.end(), bottom_interface.begin(), bottom_interface.end()); + const coordf_t interface_height = + bottom_interface_layers > 0 ? coordf_t(bottom_interface_layers) * m_slicing_params.layer_height : 0.0; + + const coordf_t layer_top_z = ts_layer->print_z; + const coordf_t layer_bottom_z = ts_layer->bottom_z(); + ExPolygons new_base_areas; + ExPolygons new_floor_areas; + struct ContactBand { + coordf_t z = 0.0; + Polygons surfaces; + }; + for (const ExPolygon& comp : base_areas) { + ExPolygons comp_poly { comp }; + bool found_contact = false; + std::vector bands; + + // Search downward for object layers whose TOP/BOTTOM surfaces intersect this component. + for (size_t idx = obj_layer_nr + 1; idx-- > 0;) { + const Layer* below_layer = m_object->get_layer(idx); + Polygons top_surfaces = collect_region_slices_by_type(*below_layer, stTop); + Polygons bottom_surfaces = collect_region_slices_by_type(*below_layer, stBottom); + Polygons surf_union = top_surfaces; + polygons_append(surf_union, bottom_surfaces); + if (surf_union.empty()) + continue; + + ExPolygons inter = intersection_ex(comp_poly, surf_union); + if (!inter.empty()) { + bands.push_back(ContactBand{ below_layer->print_z, std::move(surf_union) }); + found_contact = true; + } } + + if (found_contact) { + std::sort(bands.begin(), bands.end(), [](const ContactBand &a, const ContactBand &b) { + return a.z < b.z; + }); + } + + if (!found_contact) { + append(new_base_areas, comp_poly); + continue; + } + + bool interface_id_set = false; + bool any_gap_cleared = false; + + for (const ContactBand &band : bands) { + const coordf_t band_gap_top = band.z + bottom_gap_height; + const coordf_t band_iface_start = band_gap_top; + const bool band_applies = layer_top_z >= band.z - EPSILON; + if (!band_applies) + continue; + + + // Inside the gap: remove only the part overlapping the contact surface, keep the rest. + if (bottom_gap_height > EPSILON && layer_bottom_z < band_gap_top - EPSILON) { + any_gap_cleared = true; + comp_poly = std::move(diff_ex(comp_poly, band.surfaces)); + } + + // Overlaps interface band + if (bottom_interface_layers > 0 && + layer_bottom_z >= band_iface_start - EPSILON && + layer_bottom_z < band_iface_start + interface_height - EPSILON) { + if (!interface_id_set) { + size_t first_interface_layer = layer_nr; + while (first_interface_layer > 0) { + if (m_ts_data->layer_heights[first_interface_layer - 1].print_z <= band_iface_start + EPSILON) + break; + --first_interface_layer; + } + // ORCA: Use support-layer index for base-interface selection (robust with independent heights). + if (m_support_params.num_bottom_base_interface_layers > 0) { + const int bottom_interface_idx = + std::max(0, int(layer_nr) - int(first_interface_layer)); + const int bottom_base_start_idx = + std::max(0, int(bottom_interface_layers) - int(m_support_params.num_bottom_base_interface_layers)); + floor_interface_as_base = bottom_interface_idx >= bottom_base_start_idx; + } + interface_id_set = true; + } + + ExPolygons band_ex = union_ex(band.surfaces); + if (!band_ex.empty()) { + const coordf_t margin = scale_(m_support_params.support_extrusion_width); + ExPolygons comp_margin = offset_ex(comp_poly, margin); + ExPolygons band_clipped = intersection_ex(band_ex, comp_margin); + band_ex = std::move(band_clipped); + } + ExPolygons comp_interface = band_ex.empty() ? ExPolygons {} : intersection_ex(comp_poly, band_ex); + if (!comp_interface.empty()) { + append(new_floor_areas, comp_interface); + comp_poly = std::move(diff_ex(comp_poly, offset_ex(comp_interface, 10))); + } + } + + } + + if (any_gap_cleared && comp_poly.empty()) { + continue; + } + + if (!comp_poly.empty()) + append(new_base_areas, comp_poly); + } - if (floor_areas.empty() == false) { - //floor_areas = std::move(diff_ex(floor_areas, avoid_region_interface)); - //floor_areas = std::move(offset2_ex(floor_areas, contact_dist_scaled, -contact_dist_scaled)); - base_areas = std::move(diff_ex(base_areas, offset_ex(floor_areas, 10))); - } - } - if (bottom_gap_layers > 0 && m_ts_data->layer_heights[layer_nr].obj_layer_nr > bottom_gap_layers) { - const Layer* below_layer = m_object->get_layer(m_ts_data->layer_heights[layer_nr].obj_layer_nr - bottom_gap_layers); - ExPolygons bottom_gap_area = intersection_ex(floor_areas, below_layer->lslices); - if (!bottom_gap_area.empty()) { - floor_areas = std::move(diff_ex(floor_areas, bottom_gap_area)); - } + + + base_areas = std::move(new_base_areas); + floor_areas = std::move(new_floor_areas); } + auto &area_groups = ts_layer->area_groups; + for (auto& expoly : ts_layer->base_areas) { //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::BaseType, max_layers_above_base); @@ -2188,11 +2353,11 @@ void TreeSupport::draw_circles() for (auto& expoly : ts_layer->roof_areas) { //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::RoofType, max_layers_above_roof); - area_groups.back().interface_id = interface_id; } for (auto &expoly : ts_layer->floor_areas) { //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::FloorType, 10000); + area_groups.back().interface_as_base = floor_interface_as_base; } for (auto &expoly : ts_layer->roof_1st_layer) { //if (area(expoly) < SQ(scale_(1))) continue; @@ -2216,13 +2381,49 @@ void TreeSupport::draw_circles() //Must update bounding box which is used in avoid crossing perimeter ts_layer->lslices_bboxes.clear(); ts_layer->lslices_bboxes.reserve(ts_layer->lslices.size()); + for (const ExPolygon& expoly : ts_layer->lslices) ts_layer->lslices_bboxes.emplace_back(get_extents(expoly)); + ts_layer->backup_untyped_slices(); } }); + // ORCA: normalize interface_id sequencing to follow printed interface layers only. + const int top_base_layers = int(m_support_params.num_top_base_interface_layers); + const bool interlaced = m_object_config->support_interface_pattern == smipRectilinearInterlaced; + int roof_interface_id = 0; + int floor_interface_id = 0; + bool has_roof_interface; + bool has_floor_interface; + for (size_t layer_nr = 0; layer_nr < m_ts_data->layer_heights.size(); ++layer_nr) { + SupportLayer *ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); + if (ts_layer == nullptr) + continue; + + has_roof_interface = false; + has_floor_interface = false; + + for (auto &area_group : ts_layer->area_groups) { + if (area_group.type == SupportLayer::RoofType || area_group.type == SupportLayer::Roof1stLayer) { + if (interlaced) + area_group.interface_id = roof_interface_id; + area_group.interface_as_base = top_base_layers > 0 && roof_interface_id < top_base_layers; + has_roof_interface = true; + } else if (area_group.type == SupportLayer::FloorType) { + if (interlaced) + area_group.interface_id = floor_interface_id; + has_floor_interface = true; + } + } + + if (has_roof_interface) + ++roof_interface_id; + + if (has_floor_interface) + ++floor_interface_id; + } if (with_lightning_infill) { @@ -2488,6 +2689,7 @@ void TreeSupport::drop_nodes() layer_radius.emplace(calc_radius(node_dist)); } } + // parallel pre-compute avoidance tbb::parallel_for(tbb::blocked_range(0, contact_nodes.size() - 1), [&](const tbb::blocked_range &range) { for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) { @@ -2679,8 +2881,9 @@ void TreeSupport::drop_nodes() // Make sure the next pass doesn't drop down either of these (since that already happened). node_parent->merged_neighbours.push_front(node_parent == p_node ? neighbour : p_node); const bool to_buildplate = !is_inside_ex(get_collision(0, obj_layer_nr_next), next_position); - SupportNode* next_node = m_ts_data->create_node(next_position, node_parent->distance_to_top + 1, obj_layer_nr_next, node_parent->support_roof_layers_below - 1, to_buildplate, node_parent, - print_z_next, height_next); + SupportNode* next_node = m_ts_data->create_node(next_position, node_parent->distance_to_top + 1, obj_layer_nr_next, + node_parent->support_roof_layers_below - (node_parent->distance_to_top > 0 ? 1 : 0), + to_buildplate, node_parent, print_z_next, height_next); get_max_move_dist(next_node); m_ts_data->m_mutex.lock(); contact_nodes[layer_nr_next].push_back(next_node); @@ -2730,7 +2933,8 @@ void TreeSupport::drop_nodes() ExPolygons overhangs_next = diff_clipped({ node.overhang }, get_collision(0, obj_layer_nr_next)); for(auto& overhang:overhangs_next) { Point next_pt = overhang.contour.centroid(); - SupportNode *next_node = m_ts_data->create_node(next_pt, p_node->distance_to_top + 1, obj_layer_nr_next, p_node->support_roof_layers_below - 1, + SupportNode *next_node = m_ts_data->create_node(next_pt, p_node->distance_to_top + 1, obj_layer_nr_next, + p_node->support_roof_layers_below - (p_node->distance_to_top > 0 ? 1 : 0), to_buildplate, p_node, print_z_next, height_next); next_node->max_move_dist = 0; next_node->overhang = std::move(overhang); @@ -2876,8 +3080,9 @@ void TreeSupport::drop_nodes() } auto next_collision = get_collision(0, obj_layer_nr_next); const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[obj_layer_nr_next], next_layer_vertex); - SupportNode * next_node = m_ts_data->create_node(next_layer_vertex, node.distance_to_top + 1, obj_layer_nr_next, node.support_roof_layers_below - 1, to_buildplate, p_node, - print_z_next, height_next); + SupportNode * next_node = m_ts_data->create_node(next_layer_vertex, node.distance_to_top + 1, obj_layer_nr_next, + node.support_roof_layers_below - (node.distance_to_top > 0 ? 1 : 0), + to_buildplate, p_node, print_z_next, height_next); // don't increase radius if next node will collide partially with the object (STUDIO-7883) to_outside = projection_onto(next_collision, next_node->position); direction_to_outer = to_outside - node.position; @@ -3098,7 +3303,12 @@ std::vector TreeSupport::plan_layer_heights() // add support layers according to layer_heights int support_layer_nr = m_raft_layers; for (size_t i = 0; i < layer_heights.size(); i++, support_layer_nr++) { - SupportLayer *ts_layer = m_object->add_tree_support_layer(support_layer_nr, layer_heights[i].print_z, layer_heights[i].height, layer_heights[i].print_z); + // SupportLayer *ts_layer = m_object->add_tree_support_layer(support_layer_nr, layer_heights[i].print_z, layer_heights[i].height, layer_heights[i].print_z); + + // ORCA: add_tree_support_layer() argument order is (id, height, print_z, slice_z). + // Passing print_z as height breaks support layer geometry. + SupportLayer *ts_layer = m_object->add_tree_support_layer(support_layer_nr, layer_heights[i].height, layer_heights[i].print_z, layer_heights[i].print_z); + if (ts_layer->id() > m_raft_layers) { SupportLayer *lower_layer = m_object->get_support_layer(ts_layer->id() - 1); if (lower_layer) { @@ -3147,7 +3357,21 @@ std::vector TreeSupport::plan_layer_heights() for (SupportNode *node : contact_nodes[layer_nr]) { node->height = new_height; node->distance_to_top = -num_layers; - node->support_roof_layers_below += num_layers - 1; + } + } + + // ORCA: Recompute support_roof_layers_below from remaining interface height (independent heights). + const int top_layers = m_object->config().support_interface_top_layers.value; + if (m_support_params.independent_layer_height && top_layers > 0) { + const coordf_t interface_height_mm = coordf_t(top_layers) * m_slicing_params.layer_height; + for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { + if (contact_nodes[layer_nr].empty()) continue; + for (SupportNode *node : contact_nodes[layer_nr]) { + if (node->height <= EPSILON) continue; + const coordf_t remaining_mm = interface_height_mm - (node->dist_mm_to_top - this->top_z_distance); + const int layers_fit = remaining_mm < -EPSILON ? 0 : int(std::floor((remaining_mm + EPSILON) / node->height)); + node->support_roof_layers_below = std::min(layers_fit, top_layers); + } } } @@ -3166,9 +3390,6 @@ void TreeSupport::generate_contact_points() const coordf_t max_bridge_length = scale_(config.max_bridge_length.value); coord_t radius_scaled = scale_(base_radius); bool on_buildplate_only = m_object_config->support_on_build_plate_only.value; - const bool roof_enabled = config.support_interface_top_layers.value > 0; - const bool force_tip_to_roof = roof_enabled && m_support_params.soluble_interface; - //First generate grid points to cover the entire area of the print. BoundingBox bounding_box = m_object->bounding_box(); const Point bounding_box_size = bounding_box.max - bounding_box.min; @@ -3200,7 +3421,7 @@ void TreeSupport::generate_contact_points() // z_distance_top = round(z_distance_top / layer_height) * layer_height; // // BBS: add extra distance if thick bridge is enabled // // Note: normal support uses print_z, but tree support uses integer layers, so we need to subtract layer_height - // if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) { + // if (!m_slicing_params.zero_gap_interface_top && m_object_config->thick_bridges) { // z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height; //} // } @@ -3208,8 +3429,6 @@ void TreeSupport::generate_contact_points() int gap_layers = z_distance_top == 0 ? 0 : 1; size_t support_roof_layers = config.support_interface_top_layers.value; - if (support_roof_layers > 0) - support_roof_layers += 1; // BBS: add a normal support layer below interface (if we have interface) coordf_t thresh_angle = std::min(89.f, config.support_threshold_angle.value < EPSILON ? 30.f : config.support_threshold_angle.value); coordf_t half_overhang_distance = scale_(tan(thresh_angle * M_PI / 180.0) * layer_height / 2); @@ -3263,13 +3482,13 @@ void TreeSupport::generate_contact_points() if (force_add || !already_inserted.count(hash_pos)) { already_inserted.emplace(hash_pos); bool to_buildplate = true; - size_t roof_layers = add_interface ? support_roof_layers : 0; + size_t roof_layers = add_interface ? (support_roof_layers > 0 ? support_roof_layers - 1 : 0) : 0; // subtract 1 because the contact node itself counts as one layer // add a new node as a virtual node which acts as the invisible gap between support and object // distance_to_top=-1: it's virtual // print_z=object_layer->bottom_z: it directly contacts the bottom // height=z_distance_top: it's height is exactly the gap distance // dist_mm_to_top=0: it directly contacts the bottom - contact_node = m_ts_data->create_node(pt, -gap_layers, layer_nr-1, roof_layers + 1, to_buildplate, SupportNode::NO_PARENT, bottom_z, z_distance_top, 0, + contact_node = m_ts_data->create_node(pt, -gap_layers, layer_nr-1, roof_layers, to_buildplate, SupportNode::NO_PARENT, bottom_z, z_distance_top, 0, radius); contact_node->overhang = overhang; contact_node->is_sharp_tail = is_sharp_tail; @@ -3305,7 +3524,7 @@ void TreeSupport::generate_contact_points() } for (auto &overhang : overhangs_regular) { - bool add_interface = (force_tip_to_roof || area(overhang) > minimum_roof_area) && !is_sharp_tail; + bool add_interface = area(overhang) > minimum_roof_area && !is_sharp_tail; BoundingBox overhang_bounds = get_extents(overhang); double radius = std::clamp(unscale_(overhang_bounds.radius()), MIN_BRANCH_RADIUS, base_radius); // add supports at corners for both auto and manual overhangs, github #2008 diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index ba3008cd83..9b6758b8c2 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -54,7 +53,6 @@ #define _L(s) Slic3r::I18N::translate(s) #endif - //#define TREESUPPORT_DEBUG_SVG namespace Slic3r { @@ -132,7 +130,7 @@ static std::vector>> group_me const PrintObjectConfig &object_config = print_object.config(); if (object_config.support_top_z_distance < EPSILON) // || min_feature_size < scaled(0.1) that is the minimum line width - TreeSupportSettings::soluble = true; + TreeSupportSettings::zero_top_z_gap = true; } size_t largest_printed_mesh_idx = 0; @@ -283,16 +281,6 @@ static std::vector>> group_me //FIXME enforcer_overhang_offset is a fudge constant! enforced_overhangs = diff(offset(union_ex(enforced_overhangs), enforcer_overhang_offset), lower_layer.lslices); -#ifdef TREESUPPORT_DEBUG_SVG -// if (! intersecting_edges(enforced_overhangs).empty()) - { - static int irun = 0; - SVG::export_expolygons(debug_out_path("treesupport-self-intersections-%d.svg", ++irun), - { { { current_layer.lslices }, { "current_layer.lslices", "yellow", 0.5f } }, - { { lower_layer.lslices }, { "lower_layer.lslices", "gray", 0.5f } }, - { { union_ex(enforced_overhangs) }, { "enforced_overhangs", "red", "black", "", scaled(0.1f), 0.5f } } }); - } -#endif // TREESUPPORT_DEBUG_SVG //check_self_intersections(enforced_overhangs, "generate_overhangs - enforced overhangs2"); overhangs = overhangs.empty() ? std::move(enforced_overhangs) : union_(overhangs, enforced_overhangs); //check_self_intersections(overhangs, "generate_overhangs - enforcers"); @@ -718,7 +706,8 @@ static std::optional> polyline_sample_next_point_at_dis (support_params.interface_angle + (layer_idx & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)) : support_params.base_angle; - fill_params.density = float(roof ? support_params.interface_density : scaled(filler->spacing) / (scaled(filler->spacing) + float(support_infill_distance))); + // ORCA: use top-specific interface density after separating top/bottom settings. + fill_params.density = float(roof ? support_params.top_interface_density : scaled(filler->spacing) / (scaled(filler->spacing) + float(support_infill_distance))); fill_params.dont_adjust = true; Polylines out; @@ -1291,7 +1280,7 @@ static void generate_initial_areas( ; const size_t num_support_roof_layers = mesh_group_settings.support_roof_layers; const bool roof_enabled = num_support_roof_layers > 0; - const bool force_tip_to_roof = roof_enabled && (interface_placer.support_parameters.soluble_interface || sqr(config.min_radius) * M_PI > mesh_group_settings.minimum_roof_area); + const bool force_tip_to_roof = roof_enabled && (interface_placer.support_parameters.zero_gap_interface_top || sqr(config.min_radius) * M_PI > mesh_group_settings.minimum_roof_area); // cap for how much layer below the overhang a new support point may be added, as other than with regular support every new inserted point // may cause extra material and time cost. Could also be an user setting or differently calculated. Idea is that if an overhang // does not turn valid in double the amount of layers a slope of support angle would take to travel xy_distance, nothing reasonable will come from it. @@ -1806,11 +1795,6 @@ static void increase_areas_one_layer( // Abstract representation of the model outline. If an influence area would move through it, it could teleport through a wall. volumes.getWallRestriction(support_element_collision_radius(config, parent.state), layer_idx, parent.state.use_min_xy_dist); -#ifdef TREESUPPORT_DEBUG_SVG - SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-%d-%ld.svg", layer_idx, int(merging_area_idx)), - { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, - { { union_ex(parent.influence_area) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); -#endif // TREESUPPORT_DEBUG_SVG Polygons to_bp_data, to_model_data; coord_t radius = support_element_collision_radius(config, elem); @@ -1941,11 +1925,6 @@ static void increase_areas_one_layer( // was never made for precision in the single digit micron range. offset_slow = safe_offset_inc(parent.influence_area, extra_speed + extra_slow_speed + config.maximum_move_distance_slow, wall_restriction, safe_movement_distance, offset_independant_faster ? safe_movement_distance + radius : 0, 2); -#ifdef TREESUPPORT_DEBUG_SVG - SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-slow-%d-%ld.svg", layer_idx, int(merging_area_idx)), - { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, - { { union_ex(offset_slow) }, { "offset_slow", "red", "black", "", scaled(0.1f), 0.5f } } }); -#endif // TREESUPPORT_DEBUG_SVG } if (offset_fast.empty() && settings.increase_speed != slow_speed) { if (offset_independant_faster) @@ -1955,11 +1934,6 @@ static void increase_areas_one_layer( const coord_t delta_slow_fast = config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed); offset_fast = safe_offset_inc(offset_slow, delta_slow_fast, wall_restriction, safe_movement_distance, safe_movement_distance + radius, offset_independant_faster ? 2 : 1); } -#ifdef TREESUPPORT_DEBUG_SVG - SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-fast-%d-%ld.svg", layer_idx, int(merging_area_idx)), - { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, - { { union_ex(offset_fast) }, { "offset_fast", "red", "black", "", scaled(0.1f), 0.5f } } }); -#endif // TREESUPPORT_DEBUG_SVG } } std::optional result; @@ -3486,18 +3460,6 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons move_bounds, interface_placer, throw_on_cancel); auto t_gen = std::chrono::high_resolution_clock::now(); -#ifdef TREESUPPORT_DEBUG_SVG - for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++layer_idx) { - Polygons polys; - for (auto& area : move_bounds[layer_idx]) - append(polys, area.influence_area); - if (auto begin = move_bounds[layer_idx].begin(); begin != move_bounds[layer_idx].end()) - SVG::export_expolygons(debug_out_path("treesupport-initial_areas-%d.svg", layer_idx), - { { { union_ex(volumes.getWallRestriction(support_element_collision_radius(config, begin->state), layer_idx, begin->state.use_min_xy_dist)) }, - { "wall_restricrictions", "gray", 0.5f } }, - { { union_ex(polys) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); - } - #endif // TREESUPPORT_DEBUG_SVG // ### Propagate the influence areas downwards. This is an inherently serial operation. print.set_status(60, _L("Generating support")); @@ -3829,88 +3791,181 @@ void organic_draw_branches( const double bottom_z = layer_idx > 0 ? layer_z(slicing_params, config, layer_idx - 1) : 0.; slice_z.emplace_back(float(0.5 * (bottom_z + print_z))); } + std::vector slices = slice_mesh(partial_mesh, slice_z, mesh_slicing_params, throw_on_cancel); + + // ORCA: guard against empty slices from meshing. + if (slices.empty()) + continue; + bottom_contacts.clear(); + // ORCA: trim tiny fragments to reduce degenerate polygon booleans. + const double tiny_area = tiny_area_threshold(); //FIXME parallelize? for (LayerIndex i = 0; i < LayerIndex(slices.size()); ++i) { - slices[i] = diff_clipped(slices[i], volumes.getCollision(0, layer_begin + i, true)); // FIXME parent_uses_min || draw_area.element->state.use_min_xy_dist); - slices[i] = intersection(slices[i], volumes.m_bed_area); + // ORCA: safety offset when trimming collision/bed to improve robustness. + slices[i] = diff_clipped(slices[i], volumes.getCollision(0, layer_begin + i, true), ApplySafetyOffset::Yes); // FIXME parent_uses_min || draw_area.element->state.use_min_xy_dist); + slices[i] = intersection(slices[i], volumes.m_bed_area, ApplySafetyOffset::Yes); + remove_small(slices[i], tiny_area); } + size_t num_empty = 0; + if (slices.front().empty()) { // Some of the initial layers are empty. num_empty = std::find_if(slices.begin(), slices.end(), [](auto &s) { return !s.empty(); }) - slices.begin(); - } else { - if (branch.has_root) { - if (config.support_rests_on_model && branch.path.front()->state.to_model_gracious) { - if (config.settings.support_floor_layers > 0) - //FIXME one may just take the whole tree slice as bottom interface. - bottom_contacts.emplace_back(intersection_clipped(slices.front(), volumes.getPlaceableAreas(0, layer_begin, [] {}))); - } else if (layer_begin > 0) { - // Drop down areas that do rest non - gracefully on the model to ensure the branch actually rests on something. - struct BottomExtraSlice { - Polygons polygons; - double area; - }; - std::vector bottom_extra_slices; - Polygons rest_support; - coord_t bottom_radius = support_element_radius(config, *branch.path.front()); - // Don't propagate further than 1.5 * bottom radius. - //LayerIndex layers_propagate_max = 2 * bottom_radius / config.layer_height; - LayerIndex layers_propagate_max = 5 * bottom_radius / config.layer_height; - LayerIndex layer_bottommost = branch.path.front()->state.verylost ? - // If the tree bottom is hanging in the air, bring it down to some surface. - 0 : - //FIXME the "verylost" branches should stop when crossing another support. - std::max(0, layer_begin - layers_propagate_max); - double support_area_min_radius = M_PI * sqr(double(config.branch_radius)); - double support_area_stop = std::max(0.2 * M_PI * sqr(double(bottom_radius)), 0.5 * support_area_min_radius); - // Only propagate until the rest area is smaller than this threshold. - //double support_area_min = 0.1 * support_area_min_radius; - for (LayerIndex layer_idx = layer_begin - 1; layer_idx >= layer_bottommost; -- layer_idx) { - rest_support = diff_clipped(rest_support.empty() ? slices.front() : rest_support, volumes.getCollision(0, layer_idx, false)); - double rest_support_area = area(rest_support); - if (rest_support_area < support_area_stop) - // Don't propagate a fraction of the tree contact surface. - break; - bottom_extra_slices.push_back({ rest_support, rest_support_area }); - } - // Now remove those bottom slices that are not supported at all. -#if 0 - while (! bottom_extra_slices.empty()) { - Polygons this_bottom_contacts = intersection_clipped( - bottom_extra_slices.back().polygons, volumes.getPlaceableAreas(0, layer_begin - LayerIndex(bottom_extra_slices.size()), [] {})); - if (area(this_bottom_contacts) < support_area_min) - bottom_extra_slices.pop_back(); - else { - // At least a fraction of the tree bottom is considered to be supported. - if (config.settings.support_floor_layers > 0) - // Turn this fraction of the tree bottom into a contact layer. - bottom_contacts.emplace_back(std::move(this_bottom_contacts)); - break; - } - } -#endif - if (config.support_rests_on_model && config.settings.support_floor_layers > 0) - for (int i = int(bottom_extra_slices.size()) - 2; i >= 0; -- i) - bottom_contacts.emplace_back( - intersection_clipped(bottom_extra_slices[i].polygons, volumes.getPlaceableAreas(0, layer_begin - i - 1, [] {}))); - layer_begin -= LayerIndex(bottom_extra_slices.size()); - slices.insert(slices.begin(), bottom_extra_slices.size(), {}); - auto it_dst = slices.begin(); - for (auto it_src = bottom_extra_slices.rbegin(); it_src != bottom_extra_slices.rend(); ++ it_src) - *it_dst ++ = std::move(it_src->polygons); - } - } - - recover_pending_branch_roofs(interface_placer, branch.path, layer_begin, slices); } - layer_begin += LayerIndex(num_empty); + // ORCA: trim leading empty slices to keep layer indices aligned. + if (num_empty >= slices.size()) + continue; + + if (num_empty > 0) { + slices.erase(slices.begin(), slices.begin() + num_empty); + layer_begin += LayerIndex(num_empty); + } + + // ORCA: use the trimmed front slice as the contact reference. + Polygons slice_front_contact = slices.front(); + + if (branch.has_root) { + if (branch.path.front()->state.to_model_gracious) { + if (config.settings.support_floor_layers > 0) { + // If bottom Z gap is non-zero, keep bottom contacts even when not touching the model. + Polygons contacts; + + // ORCA: non-zero bottom Z should not be clipped by placeable areas. + if (config.support_rests_on_model && config.z_distance_bottom_layers > 0 && layer_begin > 0) + contacts = slice_front_contact; + else { + Polygons placeable = volumes.getPlaceableAreas(0, layer_begin, [] {}); + contacts = intersection_clipped(slice_front_contact, placeable, ApplySafetyOffset::Yes); + } + + remove_small(contacts, tiny_area); + + // ORCA: ensure bottom contacts exist if clipping removed them. + if (contacts.empty() && config.support_rests_on_model && layer_begin > 0 && !slice_front_contact.empty()) + contacts = slice_front_contact; + if (!contacts.empty()) + bottom_contacts.emplace_back(std::move(contacts)); + } + } else if (layer_begin > 0) { + // Drop down areas that do rest non - gracefully on the model to ensure the branch actually rests on something. + struct BottomExtraSlice { + Polygons polygons; + double area; + }; + std::vector bottom_extra_slices; + Polygons rest_support; + coord_t bottom_radius = support_element_radius(config, *branch.path.front()); + // Don't propagate further than 1.5 * bottom radius. + //LayerIndex layers_propagate_max = 2 * bottom_radius / config.layer_height; + LayerIndex layers_propagate_max = 5 * bottom_radius / config.layer_height; + LayerIndex layer_bottommost = branch.path.front()->state.verylost ? + // If the tree bottom is hanging in the air, bring it down to some surface. + 0 : + //FIXME the "verylost" branches should stop when crossing another support. + std::max(0, layer_begin - layers_propagate_max); + double support_area_min_radius = M_PI * sqr(double(config.branch_radius)); + double support_area_stop = std::max(0.2 * M_PI * sqr(double(bottom_radius)), 0.5 * support_area_min_radius); + // Only propagate until the rest area is smaller than this threshold. + //double support_area_min = 0.1 * support_area_min_radius; + for (LayerIndex layer_idx = layer_begin - 1; layer_idx >= layer_bottommost; -- layer_idx) { + LayerIndex collision_layer = (layer_idx == layer_begin - 1) ? layer_begin : layer_idx; + Polygons collision = volumes.getCollision(0, collision_layer, false); + rest_support = diff_clipped(rest_support.empty() ? slice_front_contact : rest_support, collision, ApplySafetyOffset::Yes); + remove_small(rest_support, tiny_area); + double rest_support_area = area(rest_support); + if (rest_support_area < support_area_stop) + // Don't propagate a fraction of the tree contact surface. + break; + bottom_extra_slices.push_back({ rest_support, rest_support_area }); + } + // Now remove those bottom slices that are not supported at all. +#if 0 + while (! bottom_extra_slices.empty()) { + Polygons this_bottom_contacts = intersection_clipped( + bottom_extra_slices.back().polygons, volumes.getPlaceableAreas(0, layer_begin - LayerIndex(bottom_extra_slices.size()), [] {})); + if (area(this_bottom_contacts) < support_area_min) + bottom_extra_slices.pop_back(); + else { + // At least a fraction of the tree bottom is considered to be supported. + if (config.settings.support_floor_layers > 0) + // Turn this fraction of the tree bottom into a contact layer. + bottom_contacts.emplace_back(std::move(this_bottom_contacts)); + break; + } + } +#endif + if (config.settings.support_floor_layers > 0) { + Polygons contacts; + if (!bottom_extra_slices.empty()) { + const int contact_idx = int(bottom_extra_slices.size()) - 1; // Use the lowest contact slice as the footprint. + + // ORCA: non-zero bottom Z should not be clipped by placeable areas. + if (config.support_rests_on_model && config.z_distance_bottom_layers > 0 && layer_begin > 0) + contacts = intersection_clipped(bottom_extra_slices[contact_idx].polygons, Polygons{volumes.m_bed_area}, ApplySafetyOffset::Yes); + else { + Polygons placeable = volumes.getPlaceableAreas(0, layer_begin, [] {}); + contacts = intersection_clipped(bottom_extra_slices[contact_idx].polygons, placeable, ApplySafetyOffset::Yes); + } + } else { + // Fallback: use the current contact slice when no propagation happened. + if (config.support_rests_on_model && config.z_distance_bottom_layers > 0 && layer_begin > 0) + contacts = slice_front_contact; + else { + Polygons placeable = volumes.getPlaceableAreas(0, layer_begin, [] {}); + contacts = intersection_clipped(slice_front_contact, placeable, ApplySafetyOffset::Yes); + } + } + + remove_small(contacts, tiny_area); + + if (!contacts.empty()) + bottom_contacts.emplace_back(std::move(contacts)); + + // ORCA: ensure bottom contacts exist if clipping removed them. + if (bottom_contacts.empty() && config.support_rests_on_model && layer_begin > 0 && !slice_front_contact.empty()) + bottom_contacts.emplace_back(slice_front_contact); + } + layer_begin -= LayerIndex(bottom_extra_slices.size()); + slices.insert(slices.begin(), bottom_extra_slices.size(), {}); + auto it_dst = slices.begin(); + for (auto it_src = bottom_extra_slices.rbegin(); it_src != bottom_extra_slices.rend(); ++ it_src) + *it_dst ++ = std::move(it_src->polygons); + } + + // ORCA: retain bottom contacts even when no placeable areas intersect. + if (branch.has_root && config.support_rests_on_model && branch.path.front()->state.layer_idx > 0 && + config.settings.support_floor_layers > 0 && config.z_distance_bottom_layers > 0 && + bottom_contacts.empty() && !slice_front_contact.empty()) + bottom_contacts.emplace_back(slice_front_contact); + + } + // ORCA: bottom contacts provide the footprint; interface layers are built later. + +#if 0 + //FIXME branch.has_tip seems to not be reliable. + if (branch.has_tip && interface_placer.support_parameters.has_top_contacts) + // Add top slices to top contacts / interfaces / base interfaces. + for (int i = int(branch.path.size()) - 1; i >= 0; -- i) { + const SupportElement &el = *branch.path[i]; + if (el.state.missing_roof_layers == 0) + break; + //FIXME Move or not? + interface_placer.add_roof(std::move(slices[int(slices.size()) - i - 1]), el.state.layer_idx, + interface_placer.support_parameters.num_top_interface_layers + 1 - el.state.missing_roof_layers); + } +#endif + while (! slices.empty() && slices.back().empty()) { slices.pop_back(); - -- layer_end; } + + // ORCA: recompute layer_end after trimming trailing empty slices. + layer_end = layer_begin + LayerIndex(slices.size()); + if (layer_begin < layer_end) { LayerIndex new_begin = tree.first_layer_id == -1 ? layer_begin : std::min(tree.first_layer_id, layer_begin); LayerIndex new_end = tree.first_layer_id == -1 ? layer_end : std::max(tree.first_layer_id + LayerIndex(tree.slices.size()), layer_end); @@ -3926,22 +3981,28 @@ void organic_draw_branches( } else if (LayerIndex dif = tree.first_layer_id - new_begin; dif > 0) tree.slices.insert(tree.slices.begin(), tree.first_layer_id - new_begin, {}); tree.slices.insert(tree.slices.end(), new_size - tree.slices.size(), {}); - layer_begin -= LayerIndex(num_empty); for (LayerIndex i = layer_begin; i != layer_end; ++ i) { int j = i - layer_begin; - if (Polygons &src = slices[j]; ! src.empty()) { + Polygons &src = slices[j]; + bool has_bottom_contacts = j < int(bottom_contacts.size()) && !bottom_contacts[j].empty(); + + // ORCA: preserve bottom contacts even if base polygons are empty. + if (!src.empty() || has_bottom_contacts) { Slice &dst = tree.slices[i - new_begin]; if (++ dst.num_branches > 1) { - append(dst.polygons, std::move(src)); - if (j < int(bottom_contacts.size())) + if (!src.empty()) + append(dst.polygons, std::move(src)); + if (has_bottom_contacts) append(dst.bottom_contacts, std::move(bottom_contacts[j])); } else { - dst.polygons = std::move(std::move(src)); - if (j < int(bottom_contacts.size())) + if (!src.empty()) + dst.polygons = std::move(src); + if (has_bottom_contacts) dst.bottom_contacts = std::move(bottom_contacts[j]); } } } + tree.first_layer_id = new_begin; } } @@ -3954,10 +4015,15 @@ void organic_draw_branches( Tree &tree = trees[tree_id]; for (Slice &slice : tree.slices) if (slice.num_branches > 1) { - slice.polygons = union_(slice.polygons); - slice.bottom_contacts = union_(slice.bottom_contacts); + // ORCA: avoid union_ on empty containers. + if (!slice.polygons.empty()) + slice.polygons = union_(slice.polygons); + if (!slice.bottom_contacts.empty()) + slice.bottom_contacts = union_(slice.bottom_contacts); + slice.num_branches = 1; } + throw_on_cancel(); } }, tbb::simple_partitioner()); @@ -3970,17 +4036,27 @@ void organic_draw_branches( std::vector slices(num_layers, Slice{}); for (Tree &tree : trees) if (tree.first_layer_id >= 0) { - for (LayerIndex i = tree.first_layer_id; i != tree.first_layer_id + LayerIndex(tree.slices.size()); ++ i) - if (Slice &src = tree.slices[i - tree.first_layer_id]; ! src.polygons.empty()) { + for (LayerIndex i = tree.first_layer_id; i != tree.first_layer_id + LayerIndex(tree.slices.size()); ++ i) { + Slice &src = tree.slices[i - tree.first_layer_id]; + bool has_bottom_contacts = !src.bottom_contacts.empty(); + + // ORCA: preserve bottom contacts even if base polygons are empty. + if (!src.polygons.empty() || has_bottom_contacts) { Slice &dst = slices[i]; + if (++ dst.num_branches > 1) { - append(dst.polygons, std::move(src.polygons)); - append(dst.bottom_contacts, std::move(src.bottom_contacts)); + if (!src.polygons.empty()) + append(dst.polygons, std::move(src.polygons)); + if (has_bottom_contacts) + append(dst.bottom_contacts, std::move(src.bottom_contacts)); } else { - dst.polygons = std::move(src.polygons); - dst.bottom_contacts = std::move(src.bottom_contacts); + if (!src.polygons.empty()) + dst.polygons = std::move(src.polygons); + if (has_bottom_contacts) + dst.bottom_contacts = std::move(src.bottom_contacts); } } + } } tbb::parallel_for(tbb::blocked_range(0, std::min(move_bounds.size(), slices.size()), 1), @@ -3988,8 +4064,11 @@ void organic_draw_branches( for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { Slice &slice = slices[layer_idx]; assert(intermediate_layers[layer_idx] == nullptr); - Polygons base_layer_polygons = slice.num_branches > 1 ? union_(slice.polygons) : std::move(slice.polygons); - Polygons bottom_contact_polygons = slice.num_branches > 1 ? union_(slice.bottom_contacts) : std::move(slice.bottom_contacts); + // ORCA: avoid union_ on empty inputs. + Polygons base_layer_polygons = slice.polygons.empty() ? Polygons{} : + (slice.num_branches > 1 ? union_(slice.polygons) : std::move(slice.polygons)); + Polygons bottom_contact_polygons = slice.bottom_contacts.empty() ? Polygons{} : + (slice.num_branches > 1 ? union_(slice.bottom_contacts) : std::move(slice.bottom_contacts)); if (! base_layer_polygons.empty()) { // Most of the time in this function is this union call. Can take 300+ ms when a lot of areas are to be unioned. diff --git a/src/libslic3r/Support/TreeSupportCommon.hpp b/src/libslic3r/Support/TreeSupportCommon.hpp index 39e07cfaf4..02ddada3b2 100644 --- a/src/libslic3r/Support/TreeSupportCommon.hpp +++ b/src/libslic3r/Support/TreeSupportCommon.hpp @@ -306,7 +306,7 @@ public: layer_start_bp_radius = (bp_radius - branch_radius) / bp_radius_increase_per_layer; - if (TreeSupportSettings::soluble) { + if (TreeSupportSettings::zero_top_z_gap) { // safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be large enough for performance to not suffer extremely // When for all meshes the z bottom and top distance is more than one layer though the worst case is xy_min_distance + min_feature_size // This is not the best solution, but the only one to ensure areas can not lag though walls at high maximum_move_distance. @@ -356,7 +356,7 @@ public: // some static variables dependent on other meshes that are not currently processed. // Has to be static because TreeSupportConfig will be used in TreeModelVolumes as this reduces redundancy. - inline static bool soluble = false; + inline static bool zero_top_z_gap = false; /*! * \brief Width of a single line of support. */ @@ -718,9 +718,15 @@ public: { assert(support_parameters.has_top_contacts); assert(dtt_roof <= support_parameters.num_top_interface_layers); + // ORCA: Reserve one top interface layer but only when top base-interface layers exist. + // This prevents all interface layers from being classified as base-interface layers + // and preserves correct top contact and interface behavior. + size_t interface_threshold = support_parameters.num_top_interface_layers_only(); + if (interface_threshold > 0 && support_parameters.num_top_base_interface_layers > 0) + --interface_threshold; SupportGeneratorLayersPtr &layers = dtt_roof == 0 ? this->top_contacts : - dtt_roof <= support_parameters.num_top_interface_layers_only() ? this->top_interfaces : this->top_base_interfaces; + dtt_roof <= interface_threshold ? this->top_interfaces : this->top_base_interfaces; SupportGeneratorLayer*& l = layers[insert_layer_idx]; if (l == nullptr) l = &layer_allocate_unguarded(layer_storage, dtt_roof == 0 ? SupporLayerType::TopContact : SupporLayerType::TopInterface, From cad12e4b8a2bab4d461a7534e802929c705e93a6 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 10 May 2026 10:14:35 +0300 Subject: [PATCH 026/127] Warn user for abnormal temperature differences for nozzle and bed (first layer vs other layers) (#12345) Warn for first and other layers big temperature delta Warn user if temperature differences (first layer vs other layers) for nozzle and plates are above a certain delta. Co-authored-by: SoftFever --- src/slic3r/GUI/ParamsDialog.cpp | 8 +++ src/slic3r/GUI/Tab.cpp | 105 +++++++++++++++++++++++++++++++- src/slic3r/GUI/Tab.hpp | 1 + 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ParamsDialog.cpp b/src/slic3r/GUI/ParamsDialog.cpp index 02d56298b0..740df52049 100644 --- a/src/slic3r/GUI/ParamsDialog.cpp +++ b/src/slic3r/GUI/ParamsDialog.cpp @@ -51,6 +51,14 @@ ParamsDialog::ParamsDialog(wxWindow * parent) Hide(); } #else + auto tab = dynamic_cast(m_panel->get_current_tab()); + // ORCA: Validate filament temperature pairs before closing the material settings dialog. + if (tab && !tab->validate_filament_temperature_pairs()) { + if (event.CanVeto()) + event.Veto(); + return; + } + Hide(); if (!m_editing_filament_id.empty()) { Filamentinformation *filament_info = new Filamentinformation(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 025b9cf687..206a83eab5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -61,7 +61,8 @@ #endif // WIN32 #include -#include +#include +#include namespace Slic3r { @@ -6430,6 +6431,10 @@ void Tab::transfer_options(const std::string &name_from, const std::string &name //BBS: add project embedded preset relate logic void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_project, bool from_input, std::string input_name ) { + // ORCA: Validate before opening any save-name UI for filament presets. + if (!validate_filament_temperature_pairs()) + return; + // since buttons(and choices too) don't get focus on Mac, we set focus manually // to the treectrl so that the EVT_* events are fired for the input field having // focus currently.is there anything better than this ? @@ -6984,6 +6989,104 @@ bool Tab::validate_custom_gcodes() return valid; } +// ORCA: Session-only suppression keys for temperature-pair safety warnings. +static std::unordered_set s_filament_temp_pair_warning_suppressed_for_session; + +// ORCA: Validate that first-layer and other-layer temperature pairs are within safety limits, and warn the user if not. +bool Tab::validate_filament_temperature_pairs() +{ + if (m_type != Preset::TYPE_FILAMENT || m_presets == nullptr) + return true; + + // Warn only for newly edited state, not for unchanged presets. + if (!m_presets->current_is_dirty()) + return true; + + Preset& edited_preset = m_presets->get_edited_preset(); + DynamicPrintConfig& config = edited_preset.config; + const std::string suppress_key = edited_preset.name; + // User opted out for this preset during current app session. + if (!suppress_key.empty() && s_filament_temp_pair_warning_suppressed_for_session.count(suppress_key) > 0) + return true; + + struct TempPairRule + { + wxString label; + std::string first_layer_key; + std::string other_layer_key; + int max_delta; + }; + + std::vector temp_pair_rules; + temp_pair_rules.push_back({_L("Nozzle"), "nozzle_temperature_initial_layer", "nozzle_temperature", 30}); + + // Derive bed labels/keys from curr_bed_type metadata (BedType order excludes btDefault). + if (const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); + bed_type_def != nullptr) { + for (int bt = static_cast(btPC); bt < static_cast(btCount); ++bt) { + const BedType bed_type = static_cast(bt); + const size_t label_idx = static_cast(bt - static_cast(btPC)); + const std::string first_key = get_bed_temp_1st_layer_key(bed_type); + const std::string other_key = get_bed_temp_key(bed_type); + if (first_key.empty() || other_key.empty()) + continue; + + wxString label = _(bed_type_def->enum_labels[label_idx]); + temp_pair_rules.push_back({label, first_key, other_key, 15}); + } + } + + wxString invalid_pairs; + int invalid_count = 0; + + for (const TempPairRule& rule : temp_pair_rules) { + if (!config.has(rule.first_layer_key) || !config.has(rule.other_layer_key)) + continue; + + const ConfigOptionInts* first_opt = config.option(rule.first_layer_key); + const ConfigOptionInts* other_opt = config.option(rule.other_layer_key); + if (first_opt == nullptr || other_opt == nullptr || first_opt->values.empty() || other_opt->values.empty()) + continue; + + const int first_temp = first_opt->get_at(0); + const int other_temp = other_opt->get_at(0); + + // Keep existing semantics: 0 means unsupported/off for these temperatures. + if (first_temp <= 0 || other_temp <= 0) + continue; + + const int delta = std::abs(first_temp - other_temp); + if (delta <= rule.max_delta) + continue; + + const wxString deg_c = wxString::FromUTF8("°C"); + const wxString bullet = wxString::FromUTF8("•"); + invalid_pairs += wxString::Format(_L(" - %s:\n %s first layer %d %s, other layers %d %s\n %s max delta %d %s, current delta %d %s\n"), + rule.label, bullet, first_temp, deg_c, other_temp, deg_c, bullet, rule.max_delta, deg_c, delta, deg_c); + ++invalid_count; + } + + if (invalid_count == 0) + return true; + + wxString msg_text = _L("Some first-layer and other-layer temperature pairs exceed safety limits.\n"); + msg_text += _L("\nInvalid pairs:\n"); + msg_text += invalid_pairs; + msg_text += _L("\nYou can go back to edit values, or continue if this is intentional."); + msg_text += _L("\n\nContinue anyway?"); + + RichMessageDialog dialog(parent(), msg_text, _L("Temperature Safety Check"), wxYES | wxNO | wxICON_WARNING); + dialog.SetButtonLabel(wxID_YES, _L("Continue"), true); + dialog.SetButtonLabel(wxID_NO, _L("Back")); + dialog.ShowCheckBox(_L("Don't warn again for this preset")); + const int answer = dialog.ShowModal(); + // Session-only suppression (does not modify/save filament preset data). + if (dialog.IsCheckBoxChecked() && !suppress_key.empty()) + s_filament_temp_pair_warning_suppressed_for_session.insert(suppress_key); + + return answer == wxID_YES; +} + void Tab::set_just_edit(bool just_edit) { m_just_edit = just_edit; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 5a371fd245..e529ebaed0 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -419,6 +419,7 @@ public: static bool validate_custom_gcode(const wxString& title, const std::string& gcode); bool validate_custom_gcodes(); + bool validate_filament_temperature_pairs(); bool validate_custom_gcodes_was_shown{ false }; void set_just_edit(bool just_edit); From 51d2c91c9b10108f16d58bb97d3b8a4d2102c745 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 16:26:19 +0800 Subject: [PATCH 027/127] Remap paint after reload from disk --- src/slic3r/GUI/Plater.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e95d428248..c876ca457e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -8880,6 +8880,16 @@ void Plater::priv::reload_from_disk() new_volume->convert_from_imperial_units(); else if (old_volume->source.is_converted_from_meters) new_volume->convert_from_meters(); + + // Remap paint + if (wxGetApp().app_config->get_bool("keep_painting")) { + auto saved_painting = old_volume->save_painting(); + if (saved_painting) { + saved_painting->mesh.transform(Geometry::translation_transform(new_volume->mesh().get_init_shift())); + new_volume->restore_painting(saved_painting); + } + } + std::swap(old_model_object->volumes[vol_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); if (!sinking) old_model_object->ensure_on_bed(); From 5c754e360e72c04d1091fb4188367b70f3bad4c4 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 16:33:08 +0800 Subject: [PATCH 028/127] Spatial paint remapping after replace stl --- src/slic3r/GUI/Plater.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c876ca457e..e184ad6272 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -8351,10 +8351,20 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const new_volume->convert_from_imperial_units(); else if (old_volume->source.is_converted_from_meters) new_volume->convert_from_meters(); - new_volume->supported_facets.assign(old_volume->supported_facets); - new_volume->seam_facets.assign(old_volume->seam_facets); - new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets); - new_volume->fuzzy_skin_facets.assign(old_volume->fuzzy_skin_facets); + if (wxGetApp().app_config->get_bool("keep_painting")) { + // Proper paint remapping + auto saved_painting = old_volume->save_painting(); + if (saved_painting) { + saved_painting->mesh.transform(Geometry::translation_transform(new_volume->mesh().get_init_shift())); + new_volume->restore_painting(saved_painting); + } + } else { + // Won't work well if mesh changed, but kept for old behavior + new_volume->supported_facets.assign(old_volume->supported_facets); + new_volume->seam_facets.assign(old_volume->seam_facets); + new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets); + new_volume->fuzzy_skin_facets.assign(old_volume->fuzzy_skin_facets); + } std::swap(old_model_object->volumes[volume_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); if (!sinking) From 1299fcef4ae397a2f56e05ca81b76355cbec9628 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 18:27:02 +0800 Subject: [PATCH 029/127] Remap paint after repair model --- src/slic3r/GUI/GUI_ObjectList.cpp | 7 +++++-- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 7 ++++--- src/slic3r/Utils/FixModelByCgal.cpp | 18 +++++++++++++++--- src/slic3r/Utils/FixModelByCgal.hpp | 2 +- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 9da5edf6c3..93e5c94432 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -6086,10 +6086,13 @@ void ObjectList::fix_through_cgal() msg += "\n"; } - plater->clear_before_change_mesh(obj_idx); + const bool keep_painting = GUI::wxGetApp().app_config->get_bool("keep_painting"); + if (!keep_painting) { + plater->clear_before_change_mesh(obj_idx); + } const size_t volumes_before = object(obj_idx)->volumes.size(); std::string res; - if (!fix_model_with_cgal_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res)) + if (!fix_model_with_cgal_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res, keep_painting)) return false; //wxGetApp().plater()->changed_mesh(obj_idx); object(obj_idx)->ensure_on_bed(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index c2e4a19a73..da523788b8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3321,6 +3321,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) wxBusyCursor wait; + const bool keep_painting = GUI::wxGetApp().app_config->get_bool("keep_painting"); ModelObjectCutAttributes attributes = only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | only_if(has_connectors ? false : m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) | @@ -3330,7 +3331,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) | only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo) | - only_if(wxGetApp().app_config->get_bool("keep_painting"),ModelObjectCutAttribute::KeepPaint); + only_if(keep_painting, ModelObjectCutAttribute::KeepPaint); // update cut_id for the cut object in respect to the attributes update_object_cut_id(cut_mo->cut_id, attributes, dowels_count); @@ -3363,12 +3364,12 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) // model_name failing reason std::vector> failed_models; auto plater = wxGetApp().plater(); - auto fix_and_update_progress = [this, plater](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg, + auto fix_and_update_progress = [this, plater, keep_painting](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg, std::vector &succes_models, std::vector> &failed_models) { wxString msg = _L("Repairing model object"); msg += ": " + from_u8(model_name) + "\n"; std::string res; - if (!fix_model_with_cgal_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false; + if (!fix_model_with_cgal_gui(*model_object, vol_idx, progress_dlg, msg, res, keep_painting)) return false; return true; }; ProgressDialog progress_dlg(_L("Repairing model object"), "", 100, find_toplevel_parent(plater), wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT, true); diff --git a/src/slic3r/Utils/FixModelByCgal.cpp b/src/slic3r/Utils/FixModelByCgal.cpp index e1f4320fec..9e2e014d93 100644 --- a/src/slic3r/Utils/FixModelByCgal.cpp +++ b/src/slic3r/Utils/FixModelByCgal.cpp @@ -13,6 +13,7 @@ #include "libslic3r/MeshBoolean.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/format.hpp" +#include "libslic3r/Thread.hpp" #include "../GUI/I18N.hpp" // Orca: This file provides utilities for repairing 3D model meshes using the CGAL library, handling mesh splitting, merging, and boolean operations. @@ -66,7 +67,7 @@ public: // Orca: Main function to repair model objects using CGAL, with progress dialog and cancellation support. // Returns false if fixing was canceled. fix_result contains error message if failed. -bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dialog, const wxString &msg_header, std::string &fix_result) +bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dialog, const wxString &msg_header, std::string &fix_result, bool keep_painting) { // Orca: Synchronization primitives for progress updates between worker thread and GUI. std::mutex mtx; @@ -94,8 +95,10 @@ bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::Pro }; // Orca: Worker thread that performs the actual model repair operations. - auto worker_thread = std::thread([&model_object, volume_idx, &ivolume, on_progress, &success, &canceled, &finished, &fix_result]() { + auto worker_thread = std::thread([&model_object, volume_idx, &ivolume, on_progress, &success, &canceled, &finished, &fix_result, keep_painting]() { try { + set_current_thread_name("cgal_fix_model"); + size_t start_volume = volume_idx == -1 ? 0 : size_t(volume_idx); size_t end_volume = volume_idx == -1 ? std::numeric_limits::max() : size_t(volume_idx); @@ -112,7 +115,7 @@ bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::Pro // Orca: Split splittable volumes into parts for individual processing. size_t parts_count = 1; if (volume->is_splittable()) { - parts_count = volume->split(1, false); // TODO: fix this + parts_count = volume->split(1, keep_painting); if (parts_count > 1) { const std::string msg = Slic3r::format(L("Split into %1% parts"), parts_count); on_progress(msg.c_str(), 10); @@ -150,6 +153,12 @@ bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::Pro ModelVolume *part_volume = model_object.volumes[part_idx]; TriangleMesh mesh = part_volume->mesh(); if (its_num_open_edges(mesh.its) != 0) { + + // Save painting for later remap + const std::optional saved_painting = keep_painting ? + part_volume->save_painting() : + std::optional{}; + std::string error; if (!MeshBoolean::cgal::repair(mesh, nullptr, &error)) throw Slic3r::RuntimeError(error.empty() ? L("Repair failed") : error.c_str()); @@ -158,6 +167,9 @@ bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::Pro part_volume->calculate_convex_hull(); part_volume->invalidate_convex_hull_2d(); part_volume->set_new_unique_id(); + + // Remap paint back + part_volume->restore_painting(saved_painting); } } diff --git a/src/slic3r/Utils/FixModelByCgal.hpp b/src/slic3r/Utils/FixModelByCgal.hpp index 3caa6d7fb9..61c8c91087 100644 --- a/src/slic3r/Utils/FixModelByCgal.hpp +++ b/src/slic3r/Utils/FixModelByCgal.hpp @@ -11,7 +11,7 @@ class ModelObject; class Print; // Return false if fixing was canceled. fix_result is empty on success. -extern bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result); +extern bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result, bool keep_painting); } // namespace Slic3r From 972dae22afdadc3251d05e10c2d6f00c35e6b83a Mon Sep 17 00:00:00 2001 From: Robert Baker <51850403+robertbaker@users.noreply.github.com> Date: Sun, 10 May 2026 06:20:09 -0700 Subject: [PATCH 030/127] Add Anycubic Kobra 3 Max (#11586) Fix Kobra 3 Max printable area and JSON spacing --- resources/profiles/Anycubic.json | 164 +++++++++ .../Anycubic Kobra 3 Max_buildplate_model.stl | Bin 0 -> 180784 bytes ...nycubic Kobra 3 Max_buildplate_texture.svg | 23 ++ .../Anycubic/Anycubic Kobra 3 Max_cover.png | Bin 0 -> 6309 bytes ... ABS @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ... ABS @Anycubic Kobra 3 Max 0.6 nozzle.json | 306 +++++++++++++++++ ... ABS @Anycubic Kobra 3 Max 0.8 nozzle.json | 306 +++++++++++++++++ ... ASA @Anycubic Kobra 3 Max 0.6 nozzle.json | 306 +++++++++++++++++ ... ASA @Anycubic Kobra 3 Max 0.8 nozzle.json | 306 +++++++++++++++++ .../filament/Anycubic Generic ABS.json | 3 +- .../filament/Anycubic Generic ASA.json | 1 + .../filament/Anycubic Generic PETG.json | 3 +- .../filament/Anycubic Generic PLA.json | 3 +- .../filament/Anycubic Generic TPU.json | 3 +- ... 95A @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...PETG @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...PETG @Anycubic Kobra 3 Max 0.6 nozzle.json | 297 ++++++++++++++++ ...PETG @Anycubic Kobra 3 Max 0.8 nozzle.json | 297 ++++++++++++++++ ... PLA @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ... PLA @Anycubic Kobra 3 Max 0.6 nozzle.json | 306 +++++++++++++++++ ... PLA @Anycubic Kobra 3 Max 0.8 nozzle.json | 306 +++++++++++++++++ ...peed @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...nous @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...atte @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...Silk @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ...PLA+ @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ... TPU @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ ... TPU @Anycubic Kobra 3 Max 0.6 nozzle.json | 306 +++++++++++++++++ ... TPU @Anycubic Kobra 3 Max 0.8 nozzle.json | 306 +++++++++++++++++ ...asic @Anycubic Kobra 3 Max 0.4 nozzle.json | 297 ++++++++++++++++ .../Anycubic Kobra 3 Max 0.4 nozzle.json | 265 +++++++++++++++ .../Anycubic Kobra 3 Max 0.6 nozzle.json | 235 +++++++++++++ .../Anycubic Kobra 3 Max 0.8 nozzle.json | 238 +++++++++++++ .../machine/Anycubic Kobra 3 Max.json | 13 + ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.6 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.8 nozzle.json | 320 ++++++++++++++++++ .../0.20mm Standard @Anycubic Predator.json | 12 +- ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.6 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.8 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.4 nozzle.json | 307 +++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.6 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.8 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.6 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.8 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.6 nozzle.json | 320 ++++++++++++++++++ ...dard @Anycubic Kobra 3 Max 0.8 nozzle.json | 320 ++++++++++++++++++ src/slic3r/GUI/CreatePresetsDialog.cpp | 2 +- 52 files changed, 12305 insertions(+), 11 deletions(-) create mode 100644 resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_model.stl create mode 100644 resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_texture.svg create mode 100644 resources/profiles/Anycubic/Anycubic Kobra 3 Max_cover.png create mode 100644 resources/profiles/Anycubic/filament/Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic ASA @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic ASA @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PEBA 95A @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PETG @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PETG @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PETG @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA High Speed @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA Luminous @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA Matte @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA Silk @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic PLA+ @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic TPU @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic TPU @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Anycubic TPU @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/filament/Generic PETG Basic @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/machine/Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/machine/Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/machine/Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/machine/Anycubic Kobra 3 Max.json create mode 100644 resources/profiles/Anycubic/process/0.08mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.12mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.16mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.18mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.20mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.20mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.24mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.24mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.24mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.28mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.30mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.32mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.36mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.40mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.42mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json create mode 100644 resources/profiles/Anycubic/process/0.48mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json diff --git a/resources/profiles/Anycubic.json b/resources/profiles/Anycubic.json index 7133ca042a..ea6c76d061 100644 --- a/resources/profiles/Anycubic.json +++ b/resources/profiles/Anycubic.json @@ -44,6 +44,10 @@ "name": "Anycubic Kobra 3", "sub_path": "machine/Anycubic Kobra 3.json" }, + { + "name": "Anycubic Kobra 3 Max", + "sub_path": "machine/Anycubic Kobra 3 Max.json" + }, { "name": "Anycubic Kobra Max", "sub_path": "machine/Anycubic Kobra Max.json" @@ -78,6 +82,70 @@ "name": "fdm_process_common", "sub_path": "process/fdm_process_common.json" }, + { + "name": "0.08mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.08mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.12mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.12mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.16mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.16mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.18mm Standard @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "process/0.18mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "0.20mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.20mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.20mm Standard @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "process/0.20mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "0.24mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.24mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.24mm Standard @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "process/0.24mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "0.24mm Standard @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "process/0.24mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "0.28mm Standard @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "process/0.28mm Standard @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "0.30mm Standard @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "process/0.30mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "0.32mm Standard @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "process/0.32mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "0.36mm Standard @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "process/0.36mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "0.40mm Standard @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "process/0.40mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "0.42mm Standard @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "process/0.42mm Standard @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "0.48mm Standard @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "process/0.48mm Standard @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, { "name": "0.08mm HighDetail @Anycubic Kobra 3 0.4 nozzle", "sub_path": "process/0.08mm HighDetail @Anycubic Kobra 3 0.4 nozzle.json" @@ -396,6 +464,90 @@ "name": "Anycubic PETG @Anycubic Kobra 3 0.4 nozzle", "sub_path": "filament/Anycubic PETG @Anycubic Kobra 3 0.4 nozzle.json" }, + { + "name": "Anycubic PETG @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PETG @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PETG @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "filament/Anycubic PETG @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic PETG @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "filament/Anycubic PETG @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "Anycubic PLA @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PLA @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "filament/Anycubic PLA @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic PLA @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "filament/Anycubic PLA @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "Anycubic PLA High Speed @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA High Speed @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PLA Luminous @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA Luminous @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PLA Matte @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA Matte @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PLA Silk @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA Silk @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic PLA+ @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PLA+ @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "filament/Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "filament/Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "Anycubic ASA @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "filament/Anycubic ASA @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic ASA @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "filament/Anycubic ASA @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "Anycubic PEBA 95A @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic PEBA 95A @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic TPU @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Anycubic TPU @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic TPU @Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "filament/Anycubic TPU @Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic TPU @Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "filament/Anycubic TPU @Anycubic Kobra 3 Max 0.8 nozzle.json" + }, + { + "name": "Generic PETG Basic @Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "filament/Generic PETG Basic @Anycubic Kobra 3 Max 0.4 nozzle.json" + }, { "name": "Anycubic PLA @Anycubic Kobra 2 Max 0.4 nozzle", "sub_path": "filament/Anycubic PLA @Anycubic Kobra 2 Max 0.4 nozzle.json" @@ -518,6 +670,18 @@ "name": "Anycubic Kobra 3 0.8 nozzle", "sub_path": "machine/Anycubic Kobra 3 0.8 nozzle.json" }, + { + "name": "Anycubic Kobra 3 Max 0.4 nozzle", + "sub_path": "machine/Anycubic Kobra 3 Max 0.4 nozzle.json" + }, + { + "name": "Anycubic Kobra 3 Max 0.6 nozzle", + "sub_path": "machine/Anycubic Kobra 3 Max 0.6 nozzle.json" + }, + { + "name": "Anycubic Kobra 3 Max 0.8 nozzle", + "sub_path": "machine/Anycubic Kobra 3 Max 0.8 nozzle.json" + }, { "name": "Anycubic Kobra Max 0.4 nozzle", "sub_path": "machine/Anycubic Kobra Max 0.4 nozzle.json" diff --git a/resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_model.stl b/resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_model.stl new file mode 100644 index 0000000000000000000000000000000000000000..3360c21b003b5901b359d910936a5360137377ff GIT binary patch literal 180784 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 N1>fTDhR?EA{|B1M@x}lE literal 0 HcmV?d00001 diff --git a/resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_texture.svg b/resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_texture.svg new file mode 100644 index 0000000000..a1a1285c57 --- /dev/null +++ b/resources/profiles/Anycubic/Anycubic Kobra 3 Max_buildplate_texture.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Anycubic/Anycubic Kobra 3 Max_cover.png b/resources/profiles/Anycubic/Anycubic Kobra 3 Max_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..91fc0d2b518239a9a84f05b48fa220193c3efc27 GIT binary patch literal 6309 zcmV;W7+U9vP)lpzi;Lyu<;~5_y}iBd?d{>= z;kC83xw*OB-QCsI)tZ``j*gB!JwBhGpUB9_iiwHn=;)`XsPXaf<>lqq*VoR@&attv z$H&KqhlsqqyklczdU|?9MMYU!T6T7Jv9Ym{k&$k0Zfa_3XlP~`85&enRL#xJ&d$zQ zSXivAtST!j*lieaaB-=rse^-qGcz-lYs-{9cjFMbuCMFaW6~x2CmzS3_Gc?A=#vdOaXlQ84%F26td#tRinwpxxz`(JwvGAUUkV?I2 z00013bW%=J0QfI!`u_eQ`2GP(`auR+{rau`{`n4-p7=)?{`vm;an8*+&3Vp^W9QJ9 z-&nL9SX{sO>6hyWZaJwU5?z>u$Td4}`o-LP}mB2?)rWynO$U zaL<`Z5ZkqnK;}Ma;g29l9p^XyGw002n69loT&X~7(GstI{rTTO@1umAdNt|S>rnf3 zqNqKliuFE1z>o4lzk2%HFdKg5CRHXad71cEWOQmLHKt_Y6AxfbRn3c+pCcpPQv+c0 z4IhV9D=%)XhpO1rqyKsG0z_Z=PyAPK$1lXT{tv)CMGG7FTSF0>dNFww3kGA|@p^v0 zl1jM1UfyCd9VK2FgJ&{Zm6pV9EiISA22P#rpPU`c?=b$QCC@q>y2EFVb85ZXnLngyn&y_YLJ#TG zWkoSBdK>d6E&A8A{1zUe1D~q8o=hedC`){RgQQgrA6QkBYGQ#o%xAac{{`3<2VhNG z5cqp@I0Rtvy8_NDivSbebND}D18ez@^8?ehv?P-63Apg_<8nD{eq6|5ADGwnP_FZE z_@lB&(vmnPEh${!)P8D>0$U3LhwpHV@NhWgo~3jx4`pe8eqg*-3&*k)Zb)yq2bY>s zSO}PN(h3(ib^89&(sj$)UrR-64s!_U)SL73^9$3&OJeC4=ct4ELYmipm;(1h13pkS zwWrcco@x1l0_25PvjZCv5_2d^L6!~?I0*u1P1Ev<0>GEb9KfQ;sSZyZ{yj8cEvaeL zUj&B8Hs=DCXi#$lE^+}bAh08s-Gv+m8OGo*$HKlQ7U@#zQn%oCsXI3ufH9<1RdKv{ylv}? zIE>2a4&YwupB4lLd+}D0*jYSb18bJoZK4{EWhu&|d4Ua5fnGXrKVO9RWCCnT{%)z* z3Jv&A05-iYRkPW3EYm#SnJ=Ubf#hx0(?x(2md^`gCx#82+S3b~VmE-c5r@ZS+_VbL ztC@iX(SR8&h|FPUA>adxju{4u3GG6&h9HlA59!i0`%W@%xq#}~wi^dx$5fmdFJAp@ z7%P=Z0^CbE$C(Fs=WXKPZIId%`so?sg2O#ANLr&19WLlzgYw#LqtWyf#W|aI4jY?{ z*PanL(SZCB{MsYooSxaX?z*n64#oqj@#bF}8{20ai!1S|02#X5b!{XDi`%e^*njx< zZ*OmGe7fd_J*@uS4;5z~Kq7XPUaJ zLutl0=V`T~L9{q;p0n=nJP0k18(?*}36G5dFM`!Ye#)t+P+?ihg{h zyBCX&#h#+dPs`P6z2E9wTX_fOaN7Z5uM6bhu#-!tJN0T6{#`8g?Tb%i>+B3)dJcdA zGkMg8rqqhrXnTr!^01I@|J-gjf9~N%hFyN$tQTPiCdu~*MnNLQBEh?VQXFBw{Gbo8 z>VuV^NHd;*$)#KdT;T1DT0=|KT}aSv*9G221C}@ym^0}X5|<$t34#$UEBxac5_^uV zPTn!Fb!fX>EvMU%4V0wbww+{hI zaT_g;yAB@c0pM`}TnZd!ctKG64NgWfa2OgF`UQ(_AgqT29{_Ls4*)K}78R8T;1cwf zKo48}PPGG{J9Rwt5ftXkaI~8pX0ArpW0}P=^Y}KT@0r6nSZZmi>DaF4I=FeT?l@ec z28*||);F1jw;$*?lT&!A~d|2+X8B7#Ib>@Z({}hC^kgg)$v%ns~{m(`lu_Y%r;w?X+5TxtIof zTf@Ose|SW$iucH`ACP4*y}-n1)o+@rhDWrp{^54mDzxqKI6DG^;U|iO{dp%TLNNK1 z(!}ejLG?Yx^>kJB_tna5!25O*rh*&y=)B5;EkSrmBKU(I!2@`JP7q=oU1Q#ALEaj7 zS}-7AXcUMh`Yb3j9uJPjy{76P@bHgm<=fs-4Q6pBn;yZKLQ@?uyH)O&h@YLspv>KY z4S*#8_GjYE4#TFQry#PaXUbCnCKA8e690(=)4SZSk`lf5J6~yP1Q<0k1MyKtZ8}qe zC4&=pDKO(@-(D|w%Jr%kR0y~UhVaiSiB(Mrl+-q6+Q(Q<0hV}*+xGM{Ob!AIjH^Jq zU+Flwe^cz=9v&WUt;2e&{xtVE9*?)D)pgQY@bqbH{qXQk<6kOx7dylHL>~lPA<{Kd z@}f73!?^6h!^MDXHyl`Dswx{dnh@B3kCHFkehKEfb*t&;mVS?*T6&MWzOWEuacXv1 z8O6eKuY$ZpTb~LM{5GtqabJm9_K0s!lRZkMDvd7vcKZLcP+e??q+dOHaHq+R@xbSI zjrTJ)acWNn(4$8Z+TFkRe9f{|O{HG99Y6+aU9a7SEt7kMTSHVPv_m|5H@B?x6kFZ<~n^Mm7>UCF!I{2)9Ls7bzED9b;M&WwU>KGg%-1C*37`0byf;S zBh!V21Ll=v@?hQ`ZFl3;VAz6qby|F(B8PXFHuZ?bGa$cX&)kEVfjhL)WwSYxE|e@w znfX_cQ$6|>N`;NUwudVXtj4kMfT4ZVYYgZ=*wg=!cP?CsBUv10k;r4F+1^#60?YO} z4#!r;v1LxTt9BFG-b`W+ghvus9)S>1zyCMbs#}$iC^%zN=~L(M2P5zBrUw$}@F#)cFg>N`>X+xKw#j7Zt>%BvWdQ93yTj?Ab zMQm~goZjip=VPq?J4UP?aQzl~*@-S!z{R(BC6b-6`;O%YV_-7El<5A#m4!#B_W*NC zjejx+#sePQ0nhI7018q)3g8tiE{=#&f#HwtPKJNMFNaRy}1L1xf`UftbyqabfUo*aH2uP95``5X`p$O3c-)s;topMibwT=e{CNqb*$buGU zz&}R{e8ZuI>Ev*ZeUv7L+H>mC2snx|%(I2RZV2$t(YZ7nAGAqjm|FOj%P1WYaFg45 zn0*<}(SxEkEJ`=|wQxjbxVb?t{S8hK;w@-JS`Rlj$-)V881E*z^bHx8zTK244WpLL z8-9TqN9i2QEH!y^>G{S1C&;ljx9oxGk>{J!@Mse82#lF?|A+>-&KoeCKU}|MKc)q9 zOPm5@MG&-Zn)N1^K?^I2C|&2)r6aO%lbl4eK^BG+hB%u{n=dTP{umDsud|2jElf`f zt8+L%92GDTZ!W!|z>Ua&a~omd47U~@=NjZ3?#8BAIM*OYwM1s&9Dm1Y0rI9;m;g6e zAGVa)G~k7WZ#T=rIQ(yxg;BSp&)dpTID4JOzySTnFAO~|>v+Iju7C?2Vqttr{I}gKyAKvaz;T{{XA=s1vm-_Y z{A6(-Q7i-{ia!oGiGisSyG()80E;`@yW@B!>Fet1>e}rnWC2_xrQ^EjvE&a?w&2bw z@Qf{RCRHTE3f+EVtQW-j9bOw{2UbYgdANIc*zxu7@UR<{|L7Cl-IaRj^gLbcc&pmc zbwZuxIRKoXNHT)7Sa8O8*=xLx?I^KZU>LLzFyZZYi$)>ad)VFCU7@$Tp(W%O(1aXc z2rxp1g_6?gqNj8*z0f!ft0<+PX^fwl&wC}Yprr4~LdBy|lVur3^)SKh&$=!EV-||! zt)vOG&(_RGxVz72kyAjTj8duBql+a4RO*$m(9`g%fO_PWCHf33qPioBN)dL7*QTjI zWElfPBOL*oh0LcfzxsNhOSnE@oSmHoH(1s)CVX+&ekoA~k0XdmaY8Bu)%!J|jM#Gh zg_-~NmNhUKc+%|%1z0A}Q^jhJ?|MDg9lL>2<`&(Ks%a8V`{5$Nh6+-FgdPd2gWlP; z1aBE({NHfV&ruxTrK`bR$3)X{{i3fOoh=k!8yGiNadp>CO~b(tgZk7vr;M5$}6m z9%j#$?4~N%+IR;_1pW;2QNQ!+D4zWf$PTXfC0oMiTSQzR41ECWWbOd9SLdMA2o@;Zx^ zDHv%z9ut=qPzr2YCUUUhwgt8wz?K2(TF#14LKcC} zym@mOU`*^;`k8raF9M^A`Gf{7)bJQgy*9^?EpW%! z-A!hnsetwx&t@x%`a0W6k`#<-PoZndWp=4hpg+0(^pUhVG}SR$x?ykQJVvI;pjyJf zWVQWCM|&tjhK{94It*2MoxI#C^p-^b{3J6fT_F7Vp0swFBzLf|nN3^3O%F?JSqy+< z6c|}};_5xCMbqdgB#VjaXVp>Ky24hnp)M5);CiRnGA(RjY+j>n3fnkgn%QP!;fW7i zYHO*siDdT z%Bm{iRruvaxm9J2t@N6_aDV?FzSdeep&gWA8+EY;;ocGp3q!^v1S|tErc)*L@$qro z2@)&5*C~p+zCxUSv6lcC_m-g$8xAhR0~6=h8)&#$&BVeKxK>1E7}H{VDvz_rM^{&u zg<#sEs7WuhE0#ntK=Ol^Oj?+5ZxPt=Ed*>+;I?i;*BeqOwsG`Y-@;^xUtEUeIRUN_ z;K$K2;H5vnvwEkt5}9C1i}1bp0sI@-r3a9M2Zt_U%Fw03!Xs*76s3tvs|Xmo^h>~A zCF{2?{;H8BVpd5CB8ODNL5pOQA%iT!LKhYT3zMX0GZdu*K}&Z!jw7o}QE3}$(ZcvE zq_Py^ljN0xpyegxhBV{>+4*%XObraxlCAk&1e|D4UfNvr{PiWb^;~zE%f5i>RZD^} zAem21!!Y!dqq8G)h0EH5cw0p;r`^caKmDdF*qDqfKb>tI54e%4txb}!V9gXFAKdY zq{TCkK@TJxpXPr$*62ufr!(JUI@K-)gzg^+Bqk!@?KYhab5eNYH-eo&gIHAqcT(ZT zGQF$feAbFelY4qimte`j_x0@|jl;H8ee%7sEP*qDEmpPYRSDE}!zM+Ko%U%`I+2Wa_f#s#GyId63(5QDLs+et3;kPYsFd$xi6N`zT z{hI$MyCQXpSRGEuyK#H)=r7Fq1z_Srn> printer_m {{"Anker", {"Anker M5", "Anker M5 All-Metal Hot End", "Anker M5C"}}, {"Anycubic", {"Anycubic i3 Mega S", "Anycubic Chiron", "Anycubic Vyper", "Anycubic Kobra", "Anycubic Kobra Max", "Anycubic Kobra Plus", "Anycubic 4Max Pro", "Anycubic 4Max Pro 2", "Anycubic Kobra 2", "Anycubic Kobra 2 Plus", - "Anycubic Kobra 2 Max", "Anycubic Kobra 2 Pro", "Anycubic Kobra 2 Neo", "Anycubic Kobra 3", "Anycubic Kobra S1", "Anycubic Predator", }}, + "Anycubic Kobra 2 Max", "Anycubic Kobra 2 Pro", "Anycubic Kobra 2 Neo", "Anycubic Kobra 3", "Anycubic Kobra 3 Max", "Anycubic Kobra S1", "Anycubic Predator", }}, {"Artillery", {"Artillery Sidewinder X1", "Artillery Genius", "Artillery Genius Pro", "Artillery Sidewinder X2", "Artillery Hornet", "Artillery Sidewinder X3 Pro", "Artillery Sidewinder X3 Plus", "Artillery Sidewinder X4 Pro", "Artillery Sidewinder X4 Plus"}}, {"Bambulab", {"Bambu Lab X1 Carbon", "Bambu Lab X1", "Bambu Lab X1E", "Bambu Lab P1P", "Bambu Lab P1S", From 86e74f3f481f0551e8d9b5d9e5c1fc130290f108 Mon Sep 17 00:00:00 2001 From: julianramirezarango-source Date: Sun, 10 May 2026 08:23:53 -0500 Subject: [PATCH 031/127] Add FILL3D PLA Basic, PETG, PP, PPCF, PA filament profiles (#12973) Add FILL3D additional filament profiles (PLA Basic, PETG, PETG CF, PP, PPCF, PA) Extends the FILL3D brand support in OrcaFilamentLibrary, following the PLA Turbo profile merged in #12801. New profiles: - FILL3D PLA Basic (FILL3D002 / FILL3D002SYS) - FILL3D PETG (FILL3D003 / FILL3D003SYS) - FILL3D PP (FILL3D004 / FILL3D004SYS) - FILL3D PPCF (FILL3D005 / FILL3D005SYS) - FILL3D PA (FILL3D006 / FILL3D006SYS) - FILL3D PETG CF (FILL3D007 / FILL3D007SYS) Each material has a @base.json with FILL3D-tuned settings and a minimal @System.json. Validated with orca_extra_profile_check.py: 0 errors. Co-authored-by: SoftFever --- resources/profiles/OrcaFilamentLibrary.json | 48 ++++++++++++++ .../filament/FILL3D/FILL3D PA @System.json | 9 +++ .../filament/FILL3D/FILL3D PA @base.json | 56 ++++++++++++++++ .../filament/FILL3D/FILL3D PETG @System.json | 9 +++ .../filament/FILL3D/FILL3D PETG @base.json | 53 +++++++++++++++ .../FILL3D/FILL3D PETG CF @System.json | 9 +++ .../filament/FILL3D/FILL3D PETG CF @base.json | 62 ++++++++++++++++++ .../FILL3D/FILL3D PLA Basic @System.json | 9 +++ .../FILL3D/FILL3D PLA Basic @base.json | 41 ++++++++++++ .../filament/FILL3D/FILL3D PP @System.json | 9 +++ .../filament/FILL3D/FILL3D PP @base.json | 65 +++++++++++++++++++ .../filament/FILL3D/FILL3D PPCF @System.json | 9 +++ .../filament/FILL3D/FILL3D PPCF @base.json | 65 +++++++++++++++++++ 13 files changed, 444 insertions(+) create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @base.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @base.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @base.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @base.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @base.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @System.json create mode 100644 resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @base.json diff --git a/resources/profiles/OrcaFilamentLibrary.json b/resources/profiles/OrcaFilamentLibrary.json index 2032ea3481..63c3a15596 100644 --- a/resources/profiles/OrcaFilamentLibrary.json +++ b/resources/profiles/OrcaFilamentLibrary.json @@ -1196,6 +1196,54 @@ "name": "FILL3D PLA Turbo @System", "sub_path": "filament/FILL3D/FILL3D PLA Turbo @System.json" }, + { + "name": "FILL3D PLA Basic @base", + "sub_path": "filament/FILL3D/FILL3D PLA Basic @base.json" + }, + { + "name": "FILL3D PLA Basic @System", + "sub_path": "filament/FILL3D/FILL3D PLA Basic @System.json" + }, + { + "name": "FILL3D PETG @base", + "sub_path": "filament/FILL3D/FILL3D PETG @base.json" + }, + { + "name": "FILL3D PETG @System", + "sub_path": "filament/FILL3D/FILL3D PETG @System.json" + }, + { + "name": "FILL3D PETG CF @base", + "sub_path": "filament/FILL3D/FILL3D PETG CF @base.json" + }, + { + "name": "FILL3D PETG CF @System", + "sub_path": "filament/FILL3D/FILL3D PETG CF @System.json" + }, + { + "name": "FILL3D PP @base", + "sub_path": "filament/FILL3D/FILL3D PP @base.json" + }, + { + "name": "FILL3D PP @System", + "sub_path": "filament/FILL3D/FILL3D PP @System.json" + }, + { + "name": "FILL3D PPCF @base", + "sub_path": "filament/FILL3D/FILL3D PPCF @base.json" + }, + { + "name": "FILL3D PPCF @System", + "sub_path": "filament/FILL3D/FILL3D PPCF @System.json" + }, + { + "name": "FILL3D PA @base", + "sub_path": "filament/FILL3D/FILL3D PA @base.json" + }, + { + "name": "FILL3D PA @System", + "sub_path": "filament/FILL3D/FILL3D PA @System.json" + }, { "name": "NIT PLA @System", "sub_path": "filament/NIT/NIT PLA @System.json" diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @System.json new file mode 100644 index 0000000000..d2991dc99a --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PA @System", + "from": "system", + "setting_id": "FILL3D006SYS", + "instantiation": "true", + "inherits": "FILL3D PA @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @base.json new file mode 100644 index 0000000000..64800fce25 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PA @base.json @@ -0,0 +1,56 @@ +{ + "type": "filament", + "name": "FILL3D PA @base", + "from": "system", + "filament_id": "FILL3D006", + "instantiation": "false", + "inherits": "fdm_filament_pa", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PA" + ], + "filament_density": [ + "1.04" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "close_fan_the_first_x_layers": [ + "10" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "enable_pressure_advance": [ + "1" + ], + "fan_cooling_layer_time": [ + "5" + ], + "filament_flow_ratio": [ + "0.975" + ], + "filament_retraction_length": [ + "2" + ], + "hot_plate_temp": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "nozzle_temperature": [ + "275" + ], + "nozzle_temperature_initial_layer": [ + "275" + ], + "pressure_advance": [ + "0.038" + ], + "slow_down_layer_time": [ + "1" + ] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @System.json new file mode 100644 index 0000000000..95ed331145 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PETG @System", + "from": "system", + "setting_id": "FILL3D003SYS", + "instantiation": "true", + "inherits": "FILL3D PETG @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @base.json new file mode 100644 index 0000000000..c310be8cb2 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG @base.json @@ -0,0 +1,53 @@ +{ + "type": "filament", + "name": "FILL3D PETG @base", + "from": "system", + "filament_id": "FILL3D003", + "instantiation": "false", + "inherits": "fdm_filament_pet", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PETG" + ], + "filament_density": [ + "1.27" + ], + "filament_max_volumetric_speed": [ + "28" + ], + "enable_pressure_advance": [ + "1" + ], + "filament_flow_ratio": [ + "0.94" + ], + "filament_retraction_length": [ + "0.2" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "265" + ], + "nozzle_temperature_initial_layer": [ + "265" + ], + "nozzle_temperature_range_high": [ + "285" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "pressure_advance": [ + "0.059" + ], + "slow_down_layer_time": [ + "0" + ] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @System.json new file mode 100644 index 0000000000..a5e54be1ca --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PETG CF @System", + "from": "system", + "setting_id": "FILL3D007SYS", + "instantiation": "true", + "inherits": "FILL3D PETG CF @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @base.json new file mode 100644 index 0000000000..38214eec2c --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PETG CF @base.json @@ -0,0 +1,62 @@ +{ + "type": "filament", + "name": "FILL3D PETG CF @base", + "from": "system", + "filament_id": "FILL3D007", + "instantiation": "false", + "inherits": "fdm_filament_pet", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PETG-CF" + ], + "filament_density": [ + "1.30" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "additional_cooling_fan_speed": [ + "30" + ], + "enable_pressure_advance": [ + "1" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "20" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_retraction_length": [ + "0.2" + ], + "hot_plate_temp": [ + "75" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "265" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "pressure_advance": [ + "0.04" + ], + "slow_down_layer_time": [ + "6" + ] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @System.json new file mode 100644 index 0000000000..698fc219c4 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PLA Basic @System", + "from": "system", + "setting_id": "FILL3D002SYS", + "instantiation": "true", + "inherits": "FILL3D PLA Basic @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @base.json new file mode 100644 index 0000000000..8f2ee4ddf8 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PLA Basic @base.json @@ -0,0 +1,41 @@ +{ + "type": "filament", + "name": "FILL3D PLA Basic @base", + "from": "system", + "filament_id": "FILL3D002", + "instantiation": "false", + "inherits": "fdm_filament_pla", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PLA" + ], + "filament_density": [ + "1.24" + ], + "filament_max_volumetric_speed": [ + "54" + ], + "enable_pressure_advance": [ + "1" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_retraction_length": [ + "0.2" + ], + "nozzle_temperature": [ + "235" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "pressure_advance": [ + "0.021" + ], + "slow_down_layer_time": [ + "0" + ] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @System.json new file mode 100644 index 0000000000..995aeb304e --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PP @System", + "from": "system", + "setting_id": "FILL3D004SYS", + "instantiation": "true", + "inherits": "FILL3D PP @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @base.json new file mode 100644 index 0000000000..9e74676e50 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PP @base.json @@ -0,0 +1,65 @@ +{ + "type": "filament", + "name": "FILL3D PP @base", + "from": "system", + "filament_id": "FILL3D004", + "instantiation": "false", + "inherits": "fdm_filament_pp", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PP" + ], + "filament_density": [ + "0.93" + ], + "filament_max_volumetric_speed": [ + "14" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "5" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "enable_pressure_advance": [ + "1" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "filament_flow_ratio": [ + "1.045" + ], + "filament_retraction_length": [ + "0.2" + ], + "hot_plate_temp": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "nozzle_temperature": [ + "300" + ], + "nozzle_temperature_initial_layer": [ + "295" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.085" + ], + "slow_down_layer_time": [ + "10" + ] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @System.json new file mode 100644 index 0000000000..087a168b3a --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @System.json @@ -0,0 +1,9 @@ +{ + "type": "filament", + "name": "FILL3D PPCF @System", + "from": "system", + "setting_id": "FILL3D005SYS", + "instantiation": "true", + "inherits": "FILL3D PPCF @base", + "compatible_printers": [] +} diff --git a/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @base.json b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @base.json new file mode 100644 index 0000000000..813eb8faf2 --- /dev/null +++ b/resources/profiles/OrcaFilamentLibrary/filament/FILL3D/FILL3D PPCF @base.json @@ -0,0 +1,65 @@ +{ + "type": "filament", + "name": "FILL3D PPCF @base", + "from": "system", + "filament_id": "FILL3D005", + "instantiation": "false", + "inherits": "fdm_filament_pp", + "filament_vendor": [ + "FILL3D" + ], + "filament_type": [ + "PP" + ], + "filament_density": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "17" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "5" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "enable_pressure_advance": [ + "1" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "0" + ], + "filament_flow_ratio": [ + "1.015" + ], + "filament_retraction_length": [ + "0.2" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "300" + ], + "nozzle_temperature_initial_layer": [ + "295" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.044" + ], + "slow_down_layer_time": [ + "10" + ] +} From c4c133475f555b42c8af0ff8f0fd3c8fe2514ed8 Mon Sep 17 00:00:00 2001 From: yogihybo Date: Sun, 10 May 2026 23:27:09 +1000 Subject: [PATCH 032/127] Add Repetier Gcode Flavor as option (#13126) * Fixed PrintConfig.hpp order so Repetier outputs, updated ConfigWizard to use gcode_flavor value rather than static Add Repetier to enum values and labels Update to add Repetier base profile to the setup wizard Re-order gcode_flavors in PrintConfig.hpp and PrintConfig.cpp to match Revise ConfigWizard.cpp to use gcode_flavor rather than list order Add Repetier profiles and include in custom.json (profile disables m73 and stop emit machine limits which Repetier doesn't use) * Fix JSON formatting in Custom.json * Add support for pressure advance in Repetier flavor * Add Repetier flavor show motion ability tab is visible * Refactor jerk handling for Repetier flavor * Update resources/profiles/Custom/machine/MyRepetier 0.4 nozzle.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update resources/profiles/Custom/machine/fdm_repetier_common.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/libslic3r/PrintConfig.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * add back localisation flag for Klipper * tidy up indentation and braces * Space indentation for Repetier profiles changed to tab * Fix space indentation in Custom.json file for Repetier profiles --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ian Bassi Co-authored-by: SoftFever --- resources/profiles/Custom.json | 21 +++ .../Custom/Generic Repetier Printer_cover.png | Bin 0 -> 20443 bytes .../Custom/machine/MyRepetier 0.4 nozzle.json | 20 +++ .../profiles/Custom/machine/MyRepetier.json | 12 ++ .../Custom/machine/fdm_repetier_common.json | 143 ++++++++++++++++++ .../process/0.20mm Standard @MyRepetier.json | 11 ++ .../process/fdm_process_repetier_common.json | 108 +++++++++++++ src/libslic3r/GCodeWriter.cpp | 21 ++- src/libslic3r/PrintConfig.cpp | 15 +- src/libslic3r/PrintConfig.hpp | 15 +- src/slic3r/GUI/ConfigWizard.cpp | 16 +- src/slic3r/GUI/Tab.cpp | 2 +- 12 files changed, 370 insertions(+), 14 deletions(-) create mode 100644 resources/profiles/Custom/Generic Repetier Printer_cover.png create mode 100644 resources/profiles/Custom/machine/MyRepetier 0.4 nozzle.json create mode 100644 resources/profiles/Custom/machine/MyRepetier.json create mode 100644 resources/profiles/Custom/machine/fdm_repetier_common.json create mode 100644 resources/profiles/Custom/process/0.20mm Standard @MyRepetier.json create mode 100644 resources/profiles/Custom/process/fdm_process_repetier_common.json diff --git a/resources/profiles/Custom.json b/resources/profiles/Custom.json index e81049df69..de265beb0d 100644 --- a/resources/profiles/Custom.json +++ b/resources/profiles/Custom.json @@ -16,6 +16,10 @@ "name": "Generic RRF Printer", "sub_path": "machine/MyRRF.json" }, + { + "name": "Generic Repetier Printer", + "sub_path": "machine/MyRepetier.json" + }, { "name": "Generic ToolChanger Printer", "sub_path": "machine/MyToolChanger.json" @@ -38,6 +42,11 @@ "name": "fdm_process_rrf_common", "sub_path": "process/fdm_process_rrf_common.json" }, + { + "name": "fdm_process_repetier_common", + "sub_path": "process/fdm_process_repetier_common.json" + }, + { "name": "0.08mm Extra Fine @MyKlipper", "sub_path": "process/0.08mm Extra Fine @MyKlipper.json" @@ -130,6 +139,10 @@ "name": "0.28mm Extra Draft @MyRRF", "sub_path": "process/0.28mm Extra Draft @MyRRF.json" }, + { + "name": "0.20mm Standard @MyRepetier", + "sub_path": "process/0.20mm Standard @MyRepetier.json" + }, { "name": "0.08mm Extra Fine @MyToolChanger", "sub_path": "process/0.08mm Extra Fine @MyToolChanger.json" @@ -230,6 +243,10 @@ "name": "fdm_rrf_common", "sub_path": "machine/fdm_rrf_common.json" }, + { + "name": "fdm_repetier_common", + "sub_path": "machine/fdm_repetier_common.json" + }, { "name": "MyKlipper 0.2 nozzle", "sub_path": "machine/MyKlipper 0.2 nozzle.json" @@ -254,6 +271,10 @@ "name": "MyRRF 0.4 nozzle", "sub_path": "machine/MyRRF 0.4 nozzle.json" }, + { + "name": "MyRepetier 0.4 nozzle", + "sub_path": "machine/MyRepetier 0.4 nozzle.json" + }, { "name": "MyToolChanger 0.2 nozzle", "sub_path": "machine/MyToolChanger 0.2 nozzle.json" diff --git a/resources/profiles/Custom/Generic Repetier Printer_cover.png b/resources/profiles/Custom/Generic Repetier Printer_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd571dce788112167163ad3f86863dd726ad6b1 GIT binary patch literal 20443 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 bw8dgycrDtz^u)34ggsLu3&Rrhg{c1lJ)<4T literal 0 HcmV?d00001 diff --git a/resources/profiles/Custom/machine/MyRepetier 0.4 nozzle.json b/resources/profiles/Custom/machine/MyRepetier 0.4 nozzle.json new file mode 100644 index 0000000000..c75ed0fd71 --- /dev/null +++ b/resources/profiles/Custom/machine/MyRepetier 0.4 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "name": "MyRepetier 0.4 nozzle", + "inherits": "fdm_repetier_common", + "from": "system", + "setting_id": "GM001", + "instantiation": "true", + "printer_model": "Generic Repetier Printer", + "nozzle_diameter": [ + "0.4" + ], + "printer_variant": "0.4", + "printable_area": [ + "0x0", + "250x0", + "250x250", + "0x250" + ], + "printable_height": "250" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyRepetier.json b/resources/profiles/Custom/machine/MyRepetier.json new file mode 100644 index 0000000000..7b5a291c72 --- /dev/null +++ b/resources/profiles/Custom/machine/MyRepetier.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Generic Repetier Printer", + "model_id": "my_repetier_01", + "nozzle_diameter": "0.4", + "machine_tech": "FFF", + "family": "MyPrinter", + "bed_model": "", + "bed_texture": "orcaslicer_bed_texture.svg", + "hotend_model": "", + "default_materials": "Generic ABS @System;Generic PLA @System;Generic PLA-CF @System;Generic PETG @System;Generic TPU @System;Generic ASA @System;Generic PC @System;Generic PVA @System;Generic PA @System;Generic PA-CF @System" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/fdm_repetier_common.json b/resources/profiles/Custom/machine/fdm_repetier_common.json new file mode 100644 index 0000000000..1171559086 --- /dev/null +++ b/resources/profiles/Custom/machine/fdm_repetier_common.json @@ -0,0 +1,143 @@ +{ + "type": "machine", + "name": "fdm_repetier_common", + "inherits": "fdm_machine_common", + "from": "system", + "instantiation": "false", + "gcode_flavor": "repetier", + "disable_m73": "1", + "emit_machine_limits_to_gcode": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "20000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "20000", + "20000" + ], + "machine_max_acceleration_y": [ + "20000", + "20000" + ], + "machine_max_acceleration_z": [ + "500", + "200" + ], + "machine_max_speed_e": [ + "25", + "25" + ], + "machine_max_speed_x": [ + "500", + "200" + ], + "machine_max_speed_y": [ + "500", + "200" + ], + "machine_max_speed_z": [ + "12", + "12" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "0.2", + "0.4" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "max_layer_height": [ + "0.32" + ], + "min_layer_height": [ + "0.08" + ], + "printable_height": "250", + "extruder_clearance_radius": "65", + "extruder_clearance_height_to_rod": "36", + "extruder_clearance_height_to_lid": "140", + "printer_settings_id": "", + "printer_technology": "FFF", + "printer_variant": "0.4", + "retraction_minimum_travel": [ + "1" + ], + "retract_before_wipe": [ + "70%" + ], + "retract_when_changing_layer": [ + "1" + ], + "retraction_length": [ + "0.8" + ], + "retract_length_toolchange": [ + "2" + ], + "z_hop": [ + "0.4" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retraction_speed": [ + "30" + ], + "deretraction_speed": [ + "30" + ], + "z_hop_types": "Normal Lift", + "silent_mode": "0", + "single_extruder_multi_material": "1", + "change_filament_gcode": "", + "wipe": [ + "1" + ], + "default_filament_profile": [ + "Generic PLA @System" + ], + "default_print_profile": "0.20mm Standard @MyRepetier", + "bed_exclude_area": [ + "0x0" + ], + "machine_start_gcode": "M190 S[bed_temperature_initial_layer_single]\nM109 S[nozzle_temperature_initial_layer]\nG28\nG92 E0\n", + "machine_end_gcode": "M104 S0\nM140 S0\nG92 E0\nM84\n", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n", + "machine_pause_gcode": "G91\nG1 Z10 F900\nG90\nG1 X0 Y0 F6000\n", + "scan_first_layer": "0", + "nozzle_type": "undefine", + "auxiliary_fan": "0" +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.20mm Standard @MyRepetier.json b/resources/profiles/Custom/process/0.20mm Standard @MyRepetier.json new file mode 100644 index 0000000000..bdffd3b647 --- /dev/null +++ b/resources/profiles/Custom/process/0.20mm Standard @MyRepetier.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.20mm Standard @MyRepetier", + "inherits": "fdm_process_repetier_common", + "from": "system", + "setting_id": "GP004", + "instantiation": "true", + "layer_height": "0.2", + "bottom_shell_layers": "3", + "top_shell_layers": "4" +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/fdm_process_repetier_common.json b/resources/profiles/Custom/process/fdm_process_repetier_common.json new file mode 100644 index 0000000000..3a9bc23306 --- /dev/null +++ b/resources/profiles/Custom/process/fdm_process_repetier_common.json @@ -0,0 +1,108 @@ +{ + "type": "process", + "name": "fdm_process_repetier_common", + "inherits": "fdm_process_common", + "from": "system", + "instantiation": "false", + "adaptive_layer_height": "0", + "reduce_crossing_wall": "0", + "max_travel_detour_distance": "0", + "bottom_surface_pattern": "monotonic", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_flow": "0.95", + "bridge_speed": "50", + "brim_width": "5", + "brim_object_gap": "0.1", + "compatible_printers_condition": "", + "print_sequence": "by layer", + "default_acceleration": "1000", + "top_surface_acceleration": "1000", + "travel_acceleration": "1000", + "inner_wall_acceleration": "1000", + "outer_wall_acceleration": "1000", + "bridge_no_support": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0", + "outer_wall_line_width": "0.4", + "wall_infill_order": "inner wall/outer wall/infill", + "line_width": "0.4", + "infill_direction": "45", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "initial_layer_acceleration": "500", + "initial_layer_line_width": "0.5", + "initial_layer_print_height": "0.2", + "infill_combination": "0", + "sparse_infill_line_width": "0.45", + "infill_wall_overlap": "25%", + "interface_shells": "0", + "ironing_flow": "10%", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "layer_height": "0.2", + "reduce_infill_retraction": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "detect_overhang_wall": "1", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "inner_wall_line_width": "0.45", + "wall_loops": "3", + "print_settings_id": "", + "raft_layers": "0", + "seam_position": "aligned", + "skirt_distance": "2", + "skirt_height": "1", + "skirt_loops": "0", + "minimum_sparse_infill_area": "15", + "internal_solid_infill_line_width": "0.4", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "enable_support": "0", + "resolution": "0.012", + "support_type": "normal(auto)", + "support_style": "default", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.2", + "support_filament": "0", + "support_line_width": "0.4", + "support_interface_loop_pattern": "0", + "support_interface_filament": "0", + "support_interface_top_layers": "2", + "support_interface_bottom_layers": "2", + "support_interface_spacing": "0.5", + "support_interface_speed": "40", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "2.5", + "support_speed": "60", + "support_threshold_angle": "30", + "support_object_xy_distance": "0.35", + "tree_support_branch_angle": "45", + "tree_support_wall_count": "0", + "detect_thin_wall": "0", + "top_surface_pattern": "monotonicline", + "top_surface_line_width": "0.4", + "top_shell_layers": "3", + "top_shell_thickness": "0.8", + "initial_layer_speed": "45", + "initial_layer_infill_speed": "60", + "outer_wall_speed": "60", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "top_surface_speed": "50", + "gap_infill_speed": "80", + "sparse_infill_speed": "80", + "travel_speed": "150", + "enable_prime_tower": "1", + "wipe_tower_no_sparse_layers": "0", + "prime_tower_width": "60", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "enable_arc_fitting": "0", + "compatible_printers": [ + "MyRepetier 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index a5e1c6abf1..2d18a9d5b1 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -267,6 +267,21 @@ std::string GCodeWriter::set_jerk_xy(double jerk) jerk = m_max_jerk_y; gcode << "SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=" << jerk; + + } else if (FLAVOR_IS(gcfRepetier)) { + // Repetier uses M207 for temporary Jerk and combines X/Y into a single 'X' parameter. + double jerk_xy = jerk; + + // Clamp against the X machine limit + if (m_max_jerk_x > 0 && jerk_xy > m_max_jerk_x) + jerk_xy = m_max_jerk_x; + + // Clamp against the Y machine limit as well to be safe + if (m_max_jerk_y > 0 && jerk_xy > m_max_jerk_y) + jerk_xy = m_max_jerk_y; + + // Output the lowest safe limit using ONLY the X parameter + gcode << "M207 X" << jerk_xy; } else { double jerk_x = jerk; double jerk_y = jerk; @@ -278,7 +293,7 @@ std::string GCodeWriter::set_jerk_xy(double jerk) gcode << "M205 X" << jerk_x << " Y" << jerk_y; } - + //the is_bbl check should be in the else statement above so that it doesn't inadverently added Z & E to klipper if (m_is_bbl_printers) gcode << std::setprecision(2) << " Z" << m_max_jerk_z << " E" << m_max_jerk_e; @@ -365,6 +380,10 @@ std::string GCodeWriter::set_pressure_advance(double pa) const gcode << "SET_PRESSURE_ADVANCE ADVANCE=" << std::setprecision(4) << pa << "; Override pressure advance value\n"; else if(FLAVOR_IS(gcfRepRapFirmware)) gcode << ("M572 D0 S") << std::setprecision(4) << pa << "; Override pressure advance value\n"; + else if (FLAVOR_IS(gcfRepetier)) + // Repetier M233: X is quadratic (K), Y is linear (L). + // Applying the value to both parameters simultaneously. + gcode << "M233 X" << std::setprecision(4) << pa << " Y" << std::setprecision(4) << pa << " ; Override pressure advance value\n"; else gcode << "M900 K" <enum_values.push_back("marlin"); def->enum_values.push_back("klipper"); def->enum_values.push_back("reprapfirmware"); - //def->enum_values.push_back("repetier"); + def->enum_values.push_back("repetier"); + def->enum_values.push_back("marlin2"); + //def->enum_values.push_back("reprap"); //def->enum_values.push_back("teacup"); //def->enum_values.push_back("makerware"); - def->enum_values.push_back("marlin2"); //def->enum_values.push_back("sailfish"); //def->enum_values.push_back("mach3"); //def->enum_values.push_back("machinekit"); @@ -3718,11 +3719,11 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back("Marlin(legacy)"); def->enum_labels.push_back(L("Klipper")); def->enum_labels.push_back("RepRapFirmware"); + def->enum_labels.push_back("Repetier"); + def->enum_labels.push_back("Marlin 2"); //def->enum_labels.push_back("RepRap/Sprinter"); - //def->enum_labels.push_back("Repetier"); //def->enum_labels.push_back("Teacup"); //def->enum_labels.push_back("MakerWare (MakerBot)"); - def->enum_labels.push_back("Marlin 2"); //def->enum_labels.push_back("Sailfish (MakerBot)"); //def->enum_labels.push_back("Mach3/LinuxCNC"); //def->enum_labels.push_back("Machinekit"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6d6377cc30..2b62000c1a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -31,8 +31,19 @@ namespace Slic3r { enum GCodeFlavor : unsigned char { - gcfMarlinLegacy, gcfKlipper, gcfRepRapFirmware, gcfMarlinFirmware, gcfRepRapSprinter, gcfRepetier, gcfTeacup, gcfMakerWare, gcfSailfish, gcfMach3, gcfMachinekit, - gcfSmoothie, gcfNoExtrusion + gcfMarlinLegacy, + gcfKlipper, + gcfRepRapFirmware, + gcfRepetier, + gcfMarlinFirmware, + gcfRepRapSprinter, + gcfTeacup, + gcfMakerWare, + gcfSailfish, + gcfMach3, + gcfMachinekit, + gcfSmoothie, + gcfNoExtrusion }; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index e9767fd866..be2f7278ee 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1253,9 +1253,19 @@ PageFirmware::PageFirmware(ConfigWizard *parent) void PageFirmware::apply_custom_config(DynamicPrintConfig &config) { auto sel = gcode_picker->GetSelection(); - if (sel >= 0 && (size_t)sel < gcode_opt.enum_labels.size()) { - auto *opt = new ConfigOptionEnum(static_cast(sel)); - config.set_key_value("gcode_flavor", opt); + + // Safety check: ensure selection index is within bounds + if (sel >= 0 && (size_t) sel < gcode_opt.enum_values.size()) { + std::string selected_flavor_str = gcode_opt.enum_values[sel]; + // Ensure the default value exists to prevent null pointer crashes + if (gcode_opt.default_value) { + //Clone the fully initialized option (preserves the dictionary map) + ConfigOption* opt = gcode_opt.default_value->clone(); + // Deserialize the string safely + opt->deserialize(selected_flavor_str); + // Save it to the printer configuration + config.set_key_value("gcode_flavor", opt); + } } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 206a83eab5..ae428b4970 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4851,7 +4851,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/) { size_t n_before_extruders = 2; // Count of pages before Extruder pages auto flavor = m_config->option>("gcode_flavor")->value; - bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfKlipper || flavor == gcfRepRapFirmware); + bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfKlipper || flavor == gcfRepRapFirmware || flavor == gcfRepetier); /* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages * and be cause of application crash, when try to change Preset in moment, From 44f2b4f3633ac4b900abe406947629d76e82cf42 Mon Sep 17 00:00:00 2001 From: "Byeon Ho cheol." Date: Sun, 10 May 2026 23:02:19 +0900 Subject: [PATCH 033/127] Add Cubicon xCeler-Mini printer model and material profiles (#13172) * Add Cubicon xCeler-Mini printer model and material profiles - Add xCeler-Mini machine configuration and 0.4mm nozzle profile - Add filament profiles for all Cubicon materials (PLA, PLA+, PLAi21, ABS, ABSk, ABS-A100, PETG, PC, PA-CF) for xCeler-Mini - Add default process profile for xCeler-Mini 0.4mm nozzle - Add xCeler-Mini cover image - Update Cubicon.json to register xCeler-Mini machine, filaments, process, and machine list - Update PA-CF and PLA base filament profiles (filament_max_volumetric_speed adjustment) - Fix missed per-machine filament and process profiles for xCeler-I and xCeler-Plus * fix format --------- Co-authored-by: SoftFever --- resources/profiles/Cubicon.json | 48 ++++ .../Cubicon/Cubicon xCeler-Mini_cover.png | Bin 0 -> 19594 bytes ...n ABS @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ...-A100 @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ... ABSk @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ...PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + .../Cubicon/filament/Cubicon PA-CF @base.json | 2 +- ...on PC @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ... PETG @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ...n PLA @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ... PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + ...LAi21 @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + .../Cubicon xCeler-Mini 0.4 nozzle.json | 244 ++++++++++++++++++ .../Cubicon/machine/Cubicon xCeler-Mini.json | 10 + ...fault @Cubicon xCeler-Mini 0.4 nozzle.json | 10 + 15 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 resources/profiles/Cubicon/Cubicon xCeler-Mini_cover.png create mode 100644 resources/profiles/Cubicon/filament/Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/filament/Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/machine/Cubicon xCeler-Mini 0.4 nozzle.json create mode 100644 resources/profiles/Cubicon/machine/Cubicon xCeler-Mini.json create mode 100644 resources/profiles/Cubicon/process/cubicon default @Cubicon xCeler-Mini 0.4 nozzle.json diff --git a/resources/profiles/Cubicon.json b/resources/profiles/Cubicon.json index 89645d7b2a..94ff81914b 100644 --- a/resources/profiles/Cubicon.json +++ b/resources/profiles/Cubicon.json @@ -8,6 +8,10 @@ "name": "Cubicon xCeler-I", "sub_path": "machine/Cubicon xCeler-I.json" }, + { + "name": "Cubicon xCeler-Mini", + "sub_path": "machine/Cubicon xCeler-Mini.json" + }, { "name": "Cubicon xCeler-Plus", "sub_path": "machine/Cubicon xCeler-Plus.json" @@ -34,6 +38,10 @@ "name": "cubicon default @Cubicon xCeler-I 0.4 nozzle", "sub_path": "process/cubicon default @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "cubicon default @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "process/cubicon default @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "cubicon default @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "process/cubicon default @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -88,6 +96,10 @@ "name": "Cubicon ABS @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon ABS @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon ABS @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon ABS @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -104,6 +116,10 @@ "name": "Cubicon PA-CF @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PA-CF @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PA-CF @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PA-CF @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -112,6 +128,10 @@ "name": "Cubicon PC @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PC @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PC @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PC @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -120,6 +140,10 @@ "name": "Cubicon PETG @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PETG @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PETG @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PETG @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -128,6 +152,10 @@ "name": "Cubicon PLA @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PLA @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PLA @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PLA @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -144,6 +172,10 @@ "name": "Cubicon ABS-A100 @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon ABS-A100 @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon ABS-A100 @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon ABS-A100 @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -152,6 +184,10 @@ "name": "Cubicon ABSk @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon ABSk @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon ABSk @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon ABSk @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -160,6 +196,10 @@ "name": "Cubicon PLA+ @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PLA+ @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PLA+ @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PLA+ @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -168,6 +208,10 @@ "name": "Cubicon PLAi21 @Cubicon xCeler-I 0.4 nozzle", "sub_path": "filament/Cubicon PLAi21 @Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "filament/Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon PLAi21 @Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "filament/Cubicon PLAi21 @Cubicon xCeler-Plus 0.4 nozzle.json" @@ -182,6 +226,10 @@ "name": "Cubicon xCeler-I 0.4 nozzle", "sub_path": "machine/Cubicon xCeler-I 0.4 nozzle.json" }, + { + "name": "Cubicon xCeler-Mini 0.4 nozzle", + "sub_path": "machine/Cubicon xCeler-Mini 0.4 nozzle.json" + }, { "name": "Cubicon xCeler-Plus 0.4 nozzle", "sub_path": "machine/Cubicon xCeler-Plus 0.4 nozzle.json" diff --git a/resources/profiles/Cubicon/Cubicon xCeler-Mini_cover.png b/resources/profiles/Cubicon/Cubicon xCeler-Mini_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..9474c2d5ed751dfc1b6741271bd0a6539ae2c7c9 GIT binary patch literal 19594 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/Cubicon/filament/Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..fc7c587a79 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon ABS @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon ABS @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..251c62da89 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon ABS-A100 @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon ABS-A100 @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..c29ccfcd94 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon ABSk @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon ABSk @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..be8baf2290 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PA-CF @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PA-CF @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PA-CF @base.json b/resources/profiles/Cubicon/filament/Cubicon PA-CF @base.json index 16fcbe0d83..19893bff84 100644 --- a/resources/profiles/Cubicon/filament/Cubicon PA-CF @base.json +++ b/resources/profiles/Cubicon/filament/Cubicon PA-CF @base.json @@ -37,7 +37,7 @@ "0.99" ], "filament_max_volumetric_speed": [ - "10" + "7" ], "nozzle_temperature_initial_layer": [ "265" diff --git a/resources/profiles/Cubicon/filament/Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..010426e159 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PC @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PC @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..f235fdae31 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PETG @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PETG @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..a20941edc4 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PLA @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PLA @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..ed368f5214 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PLA+ @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PLA+ @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/filament/Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/filament/Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..10ddfff715 --- /dev/null +++ b/resources/profiles/Cubicon/filament/Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "Cubicon PLAi21 @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "Cubicon PLAi21 @base", + "from": "system", + "instantiation": "true", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} diff --git a/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..1bb60aa4bb --- /dev/null +++ b/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,244 @@ +{ + "type": "machine", + "name": "Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "fdm_machine_common", + "from": "system", + "instantiation": "true", + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_filament_profile": [ + "Cubicon PLA @Cubicon xCeler-Mini" + ], + "default_print_profile": "cubicon default @base", + "deretraction_speed": [ + "30" + ], + "disable_m73": "0", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "140", + "extruder_clearance_height_to_rod": "36", + "extruder_clearance_radius": "65", + "extruder_colour": [ + "#FCE94F" + ], + "extruder_offset": [ + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0" + ], + "machine_end_gcode": "END_PRINT", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "500", + "5000" + ], + "machine_max_acceleration_extruding": [ + "5000", + "20000" + ], + "machine_max_acceleration_x": [ + "13000", + "20000" + ], + "machine_max_acceleration_y": [ + "13000", + "20000" + ], + "machine_max_acceleration_z": [ + "250", + "500" + ], + "machine_max_speed_z": [ + "25", + "12" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "13000", + "13000" + ], + "machine_max_jerk_e": [ + "20", + "20" + ], + "machine_max_jerk_x": [ + "20", + "20" + ], + "machine_max_jerk_y": [ + "20", + "20" + ], + "machine_max_jerk_z": [ + "20", + "20" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "50", + "50" + ], + "machine_max_speed_x": [ + "500", + "500" + ], + "machine_max_speed_y": [ + "500", + "500" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "PAUSE", + "machine_start_gcode": "START_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]", + "machine_tool_change_time": "0", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.3" + ], + "min_layer_height": [ + "0.1" + ], + "nozzle_diameter": [ + "0.4" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "brass", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "print_host": "", + "print_host_webui": "", + "printable_area": [ + "0x0", + "150x0", + "150x150", + "0x150" + ], + "printable_height": "150", + "printer_model": "Cubicon xCeler-Mini", + "printer_notes": "", + "printer_settings_id": "Cubicon xCeler-Mini 0.4 nozzle", + "printer_structure": "undefine", + "printer_technology": "FFF", + "printer_variant": "0.4", + "printhost_apikey": "", + "printhost_authorization_type": "key", + "printhost_cafile": "", + "printhost_password": "", + "printhost_port": "", + "printhost_ssl_ignore_revoke": "0", + "printhost_user": "", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "retract_before_wipe": [ + "0%" + ], + "retract_length_toolchange": [ + "1" + ], + "retract_lift_above": [ + "0" + ], + "retract_lift_below": [ + "0" + ], + "retract_lift_enforce": [ + "All Surfaces" + ], + "retract_on_top_layer": [ + "0" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retract_when_changing_layer": [ + "0" + ], + "retraction_distances_when_cut": [ + "18" + ], + "retraction_length": [ + "0.8" + ], + "retraction_minimum_travel": [ + "1" + ], + "retraction_speed": [ + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "1", + "support_air_filtration": "0", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "0", + "template_custom_gcode": "", + "thumbnails": "48x48/PNG, 300x300/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3" + ], + "upward_compatible_machine": [], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "wipe": [ + "0" + ], + "wipe_distance": [ + "2" + ], + "z_hop": [ + "0.2" + ], + "z_hop_types": [ + "Normal Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini.json b/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini.json new file mode 100644 index 0000000000..af43717058 --- /dev/null +++ b/resources/profiles/Cubicon/machine/Cubicon xCeler-Mini.json @@ -0,0 +1,10 @@ +{ + "type": "machine_model", + "name": "Cubicon xCeler-Mini", + "nozzle_diameter": "0.4", + "bed_model": "", + "bed_texture": "Cubicon xCeler-I_bed_texture.svg", + "family": "Cubicon", + "machine_tech": "FFF", + "default_materials": "Cubicon PLA @Cubicon xCeler-Mini" +} diff --git a/resources/profiles/Cubicon/process/cubicon default @Cubicon xCeler-Mini 0.4 nozzle.json b/resources/profiles/Cubicon/process/cubicon default @Cubicon xCeler-Mini 0.4 nozzle.json new file mode 100644 index 0000000000..fc67c0ddd8 --- /dev/null +++ b/resources/profiles/Cubicon/process/cubicon default @Cubicon xCeler-Mini 0.4 nozzle.json @@ -0,0 +1,10 @@ +{ + "type": "process", + "name": "cubicon default @Cubicon xCeler-Mini 0.4 nozzle", + "inherits": "cubicon common @base", + "instantiation": "true", + "print_settings_id": "cubicon default @Cubicon xCeler-Mini 0.4 nozzle", + "compatible_printers": [ + "Cubicon xCeler-Mini 0.4 nozzle" + ] +} From a0d1ccaf28262b1e5e7e2f6e8235fa17482bde50 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 20:01:50 +0800 Subject: [PATCH 034/127] Refactor planar cut code so it can be reused by other cut type --- src/libslic3r/CutUtils.cpp | 64 +++++++++++++++++++++++++------------- src/libslic3r/Model.hpp | 1 + 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 7fc21bb3b4..9fc6f13c2a 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -8,7 +8,6 @@ #include "ObjectID.hpp" #include -#include namespace Slic3r { @@ -62,9 +61,10 @@ static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelV assert(vol->config.id() != src_volume->config.id()); vol->set_material(src_volume->material_id(), *src_volume->material()); vol->cut_info = src_volume->cut_info; + vol->cut_info.source_volume = src_volume->id(); } -static void process_volume_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, +static void process_volume_cut( const ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes, TriangleMesh& upper_mesh, TriangleMesh& lower_mesh) { const auto volume_matrix = volume->get_matrix(); @@ -179,9 +179,8 @@ static void process_modifier_cut(ModelVolume* volume, const Transform3d& instanc lower->add_volume(*volume); } -static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, - const std::optional& saved_painting) +static void process_solid_part_cut(const ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) { // Perform cut TriangleMesh upper_mesh, lower_mesh; @@ -190,27 +189,19 @@ static void process_solid_part_cut(ModelVolume* volume, const Transform3d& insta // Add required cut parts to the objects if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { - if (!upper_mesh.empty()) { - add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); - upper->volumes.back()->restore_painting(saved_painting); - } + add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); if (!lower_mesh.empty()) { add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); upper->volumes.back()->cut_info.is_from_upper = false; - upper->volumes.back()->restore_painting(saved_painting); } return; } - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper_mesh.empty()) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) add_cut_volume(upper_mesh, upper, volume, cut_matrix); - upper->volumes.back()->restore_painting(saved_painting); - } - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) add_cut_volume(lower_mesh, lower, volume, cut_matrix); - lower->volumes.back()->restore_painting(saved_painting); - } } static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, @@ -259,8 +250,12 @@ Cut::Cut(const ModelObject* object, int instance, const Transform3d& cut_matrix, : m_instance(instance), m_cut_matrix(cut_matrix), m_attributes(attributes) { m_model = Model(); - if (object) - m_model.add_object(*object); + if (object) { + const auto obj = m_model.add_object(*object); + for (int i = 0; i < obj->volumes.size(); i++) { + obj->volumes[i]->cut_info.source_volume = object->volumes[i]->id(); + } + } } void Cut::post_process(ModelObject* object, ModelObjectPtrs& cut_object_ptrs, bool keep, bool place_on_cut, bool flip) @@ -291,7 +286,20 @@ void Cut::post_process(ModelObject* upper, ModelObject* lower, ModelObjectPtrs& void Cut::finalize(const ModelObjectPtrs& objects) { - //clear model from temporarry objects + for (const auto obj : objects) { + for (const auto v : obj->volumes) { + if (v->cut_info.source_volume.valid()) { + for (const auto src : m_model.objects.front()->volumes) { + if (src->id() == v->cut_info.source_volume) { + v->cut_info.source_volume = src->cut_info.source_volume; + break; + } + } + } + } + } + + //clear model from temporary objects m_model.clear_objects(); // add to model result objects @@ -350,8 +358,22 @@ const ModelObjectPtrs& Cut::perform_with_plane() else process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels); } - else if (!volume->mesh().empty()) - process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, saved_painting); + else if (!volume->mesh().empty()) { + process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower); + + // Apply paint to volumes cut from current volume + if (saved_painting) { + auto apply_paint = [&saved_painting, &volume](const ModelObject* obj) { + for (const auto v : obj->volumes) { + if (v->cut_info.source_volume == volume->id()) { + v->restore_painting(saved_painting); + } + } + }; + apply_paint(upper); + apply_paint(lower); + } + } } // Post-process cut parts diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d8697adb41..eeec2783d3 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -825,6 +825,7 @@ public: CutConnectorType connector_type{ CutConnectorType::Plug }; float radius_tolerance{ 0.f };// [0.f : 1.f] float height_tolerance{ 0.f };// [0.f : 1.f] + ObjectID source_volume; // id of the volume from input model that this one is cut from CutInfo() = default; CutInfo(CutConnectorType type, float rad_tolerance, float h_tolerance, bool processed = false) : From cd826d0207eb8c47e6db8e9a3696f9fbd284f403 Mon Sep 17 00:00:00 2001 From: FlashforgeUser <144670305+FlashforgeOfficial@users.noreply.github.com> Date: Sun, 10 May 2026 22:13:28 +0800 Subject: [PATCH 035/127] Add Flashforge printer profile for Creator 5, Creator 5 Pro. (#13259) * Add Flashforge printer profile for Creator 5, Creator 5 Pro. * Add Flashforge printer png for Creator 5, Creator 5 Pro. * fix Flashforge printer profile for Creator 5, Creator 5 Pro. * Add Flashforge printer profile for Creator 5, Creator 5 Pro. --------- Co-authored-by: Ian Bassi Co-authored-by: SoftFever --- resources/profiles/Flashforge.json | 374 +++++++++++++++++- .../Flashforge Creator 5 Pro_cover.png | Bin 0 -> 106000 bytes .../Flashforge/Flashforge Creator 5_cover.png | Bin 0 -> 91283 bytes .../filament/Flashforge ABS Basic @FF C5.json | 70 ++++ .../Flashforge ABS Basic @FF C5P.json | 76 ++++ .../filament/Flashforge ABS-GF @FF C5.json | 76 ++++ .../filament/Flashforge ABS-GF @FF C5P.json | 82 ++++ .../filament/Flashforge ASA Basic @FF C5.json | 73 ++++ .../Flashforge ASA Basic @FF C5P.json | 79 ++++ .../filament/Flashforge ASA-CF @FF C5.json | 76 ++++ .../filament/Flashforge ASA-CF @FF C5P.json | 82 ++++ .../filament/Flashforge ASA-GF @FF C5.json | 76 ++++ .../filament/Flashforge ASA-GF @FF C5P.json | 82 ++++ .../filament/Flashforge HIPS @FF C5.json | 73 ++++ .../filament/Flashforge HIPS @FF C5P.json | 73 ++++ .../filament/Flashforge HS PETG @FF C5.json | 94 +++++ .../filament/Flashforge HS PETG @FF C5P.json | 97 +++++ .../filament/Flashforge HS PLA @FF C5.json | 82 ++++ .../filament/Flashforge HS PLA @FF C5P.json | 73 ++++ .../filament/Flashforge PA-CF @FF C5.json | 46 +++ .../filament/Flashforge PA-CF @FF C5P.json | 55 +++ .../filament/Flashforge PAHT-CF @FF C5.json | 82 ++++ .../filament/Flashforge PAHT-CF @FF C5P.json | 88 +++++ .../filament/Flashforge PET-CF @FF C5.json | 106 +++++ .../filament/Flashforge PET-CF @FF C5P.json | 112 ++++++ .../filament/Flashforge PETG Pro @FF C5.json | 88 +++++ .../filament/Flashforge PETG Pro @FF C5P.json | 91 +++++ .../Flashforge PETG Transparent @FF C5.json | 88 +++++ .../Flashforge PETG Transparent @FF C5P.json | 91 +++++ .../filament/Flashforge PETG-CF @FF C5.json | 91 +++++ .../filament/Flashforge PETG-CF @FF C5P.json | 91 +++++ .../Flashforge PLA Matte @FF C5.json | 82 ++++ .../Flashforge PLA Matte @FF C5P.json | 73 ++++ .../Flashforge PLA Metal @FF C5.json | 79 ++++ .../Flashforge PLA Metal @FF C5P.json | 70 ++++ .../filament/Flashforge PLA Pro @FF C5.json | 82 ++++ .../filament/Flashforge PLA Pro @FF C5P.json | 73 ++++ .../filament/Flashforge PLA Basic @FF C5.json | 118 ++++++ .../Flashforge PLA Basic @FF C5P.json | 73 ++++ .../Flashforge PLA Color Change @FF C5.json | 82 ++++ .../Flashforge PLA Color Change @FF C5P.json | 73 ++++ .../Flashforge PLA Galaxy @FF C5.json | 82 ++++ .../Flashforge PLA Galaxy @FF C5P.json | 73 ++++ .../Flashforge PLA Luminous @FF C5.json | 82 ++++ .../Flashforge PLA Luminous @FF C5P.json | 73 ++++ .../filament/Flashforge PLA Silk @FF C5.json | 85 ++++ .../filament/Flashforge PLA Silk @FF C5P.json | 76 ++++ .../filament/Flashforge PLA-CF @FF C5.json | 79 ++++ .../filament/Flashforge PLA-CF @FF C5P.json | 70 ++++ .../filament/Flashforge PPA-CF @FF C5.json | 37 ++ .../filament/Flashforge PPA-CF @FF C5P.json | 43 ++ .../filament/Flashforge PPS-CF @FF C5.json | 73 ++++ .../filament/Flashforge PPS-CF @FF C5P.json | 79 ++++ .../filament/Flashforge PVA @FF C5.json | 88 +++++ .../filament/Flashforge PVA @FF C5P.json | 91 +++++ .../filament/Flashforge TPU-64D @FF C5.json | 106 +++++ .../filament/Flashforge TPU-64D @FF C5P.json | 97 +++++ .../filament/Flashforge TPU-90A @FF C5.json | 103 +++++ .../filament/Flashforge TPU-90A @FF C5P.json | 106 +++++ .../filament/Flashforge TPU-95A @FF C5.json | 106 +++++ .../filament/Flashforge TPU-95A @FF C5P.json | 97 +++++ .../filament/FusRock PAHT-CF @FF C5.json | 82 ++++ .../filament/FusRock PAHT-CF @FF C5P.json | 88 +++++ .../filament/FusRock S-Multi @FF C5.json | 97 +++++ .../filament/FusRock S-Multi @FF C5P.json | 103 +++++ .../filament/FusRock S-PAHT @FF C5.json | 79 ++++ .../filament/FusRock S-PAHT @FF C5P.json | 85 ++++ .../filament/Generic BVOH @FF C5.json | 73 ++++ .../filament/Generic BVOH @FF C5P.json | 73 ++++ .../filament/Generic PLA @FF C5.json | 118 ++++++ .../filament/Generic PLA @FF C5P.json | 73 ++++ .../filament/Generic PLA Silk @FF C5.json | 85 ++++ .../filament/Generic PLA Silk @FF C5P.json | 76 ++++ .../filament/Generic TPU-64D @FF C5.json | 106 +++++ .../filament/Generic TPU-64D @FF C5P.json | 97 +++++ .../filament/Generic TPU-90A @FF C5.json | 103 +++++ .../filament/Generic TPU-90A @FF C5P.json | 94 +++++ .../filament/Generic TPU-95A @FF C5.json | 106 +++++ .../filament/Generic TPU-95A @FF C5P.json | 97 +++++ .../flashforge_c5_buildplate_model.stl | Bin 0 -> 20284 bytes .../flashforge_c5_buildplate_texture.png | Bin 0 -> 92605 bytes .../Flashforge Creator 5 0.4 nozzle.json | 313 +++++++++++++++ .../Flashforge Creator 5 0.6 nozzle.json | 315 +++++++++++++++ .../Flashforge Creator 5 0.8 nozzle.json | 313 +++++++++++++++ .../Flashforge Creator 5 Pro 0.4 nozzle.json | 311 +++++++++++++++ .../Flashforge Creator 5 Pro 0.6 nozzle.json | 313 +++++++++++++++ .../Flashforge Creator 5 Pro 0.8 nozzle.json | 313 +++++++++++++++ .../machine/Flashforge Creator 5 Pro.json | 12 + .../machine/Flashforge Creator 5.json | 12 + .../process/0.12mm Standard @FF C5.json | 50 +++ .../0.18mm Standard @FF C5 0.6 nozzle.json | 63 +++ .../process/0.20mm Standard @FF C5.json | 48 +++ .../process/0.24mm Standard @FF C5.json | 52 +++ .../0.30mm Standard @FF C5 0.6 nozzle.json | 65 +++ .../0.32mm Standard @FF C5 0.8 nozzle.json | 66 ++++ .../0.42mm Standard @FF C5 0.6 nozzle.json | 65 +++ .../0.48mm Standard @FF C5 0.8 nozzle.json | 66 ++++ .../0.4mm Standard @FF C5 0.8 nozzle.json | 66 ++++ 98 files changed, 9195 insertions(+), 1 deletion(-) create mode 100644 resources/profiles/Flashforge/Flashforge Creator 5 Pro_cover.png create mode 100644 resources/profiles/Flashforge/Flashforge Creator 5_cover.png create mode 100644 resources/profiles/Flashforge/filament/Flashforge ABS Basic @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ABS Basic @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ABS-GF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ABS-GF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA Basic @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA Basic @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA-GF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge ASA-GF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HIPS @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HIPS @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HS PETG @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HS PETG @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HS PLA @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge HS PLA @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PA-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PA-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PAHT-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PAHT-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PET-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PET-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG Pro @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG Pro @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG Transparent @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG Transparent @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PETG-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Matte @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Matte @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Metal @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Metal @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Pro @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Pro @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Basic @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Basic @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Color Change @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Color Change @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Galaxy @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Galaxy @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Luminous @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Luminous @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Silk @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA Silk @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PLA-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PPA-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PPA-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PPS-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PPS-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PVA @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge PVA @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-64D @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-64D @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-90A @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-90A @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-95A @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Flashforge TPU-95A @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/FusRock PAHT-CF @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/FusRock PAHT-CF @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/FusRock S-Multi @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/FusRock S-Multi @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/FusRock S-PAHT @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/FusRock S-PAHT @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic BVOH @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic BVOH @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic PLA @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic PLA @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic PLA Silk @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic PLA Silk @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-64D @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-64D @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-90A @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-90A @FF C5P.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-95A @FF C5.json create mode 100644 resources/profiles/Flashforge/filament/Generic TPU-95A @FF C5P.json create mode 100644 resources/profiles/Flashforge/flashforge_c5_buildplate_model.stl create mode 100644 resources/profiles/Flashforge/flashforge_c5_buildplate_texture.png create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 0.4 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 0.6 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 0.8 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.4 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.6 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.8 nozzle.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro.json create mode 100644 resources/profiles/Flashforge/machine/Flashforge Creator 5.json create mode 100644 resources/profiles/Flashforge/process/0.12mm Standard @FF C5.json create mode 100644 resources/profiles/Flashforge/process/0.18mm Standard @FF C5 0.6 nozzle.json create mode 100644 resources/profiles/Flashforge/process/0.20mm Standard @FF C5.json create mode 100644 resources/profiles/Flashforge/process/0.24mm Standard @FF C5.json create mode 100644 resources/profiles/Flashforge/process/0.30mm Standard @FF C5 0.6 nozzle.json create mode 100644 resources/profiles/Flashforge/process/0.32mm Standard @FF C5 0.8 nozzle.json create mode 100644 resources/profiles/Flashforge/process/0.42mm Standard @FF C5 0.6 nozzle.json create mode 100644 resources/profiles/Flashforge/process/0.48mm Standard @FF C5 0.8 nozzle.json create mode 100644 resources/profiles/Flashforge/process/0.4mm Standard @FF C5 0.8 nozzle.json diff --git a/resources/profiles/Flashforge.json b/resources/profiles/Flashforge.json index b53a32b74f..2cc425021e 100644 --- a/resources/profiles/Flashforge.json +++ b/resources/profiles/Flashforge.json @@ -1,7 +1,7 @@ { "name": "Flashforge", "url": "", - "version": "02.03.02.70", + "version": "02.03.02.60", "force_update": "0", "description": "Flashforge configurations", "machine_model_list": [ @@ -44,6 +44,14 @@ { "name": "Flashforge Guider4 Pro", "sub_path": "machine/Flashforge Guider4 Pro.json" + }, + { + "name": "Flashforge Creator 5", + "sub_path":"machine/Flashforge Creator 5.json" + }, + { + "name": "Flashforge Creator 5 Pro", + "sub_path":"machine/Flashforge Creator 5 Pro.json" } ], "process_list": [ @@ -474,6 +482,42 @@ { "name": "0.56mm Draft @FF AD5X 0.8 nozzle", "sub_path": "process/0.56mm Draft @FF AD5X 0.8 nozzle.json" + }, + { + "name": "0.12mm Standard @FF C5", + "sub_path": "process/0.12mm Standard @FF C5.json" + }, + { + "name": "0.20mm Standard @FF C5", + "sub_path": "process/0.20mm Standard @FF C5.json" + }, + { + "name": "0.24mm Standard @FF C5", + "sub_path": "process/0.24mm Standard @FF C5.json" + }, + { + "name": "0.18mm Standard @FF C5 0.6 nozzle", + "sub_path": "process/0.18mm Standard @FF C5 0.6 nozzle.json" + }, + { + "name": "0.30mm Standard @FF C5 0.6 nozzle", + "sub_path": "process/0.30mm Standard @FF C5 0.6 nozzle.json" + }, + { + "name": "0.42mm Standard @FF C5 0.6 nozzle", + "sub_path": "process/0.42mm Standard @FF C5 0.6 nozzle.json" + }, + { + "name": "0.32mm Standard @FF C5 0.8 nozzle", + "sub_path": "process/0.32mm Standard @FF C5 0.8 nozzle.json" + }, + { + "name": "0.48mm Standard @FF C5 0.8 nozzle", + "sub_path": "process/0.48mm Standard @FF C5 0.8 nozzle.json" + }, + { + "name": "0.4mm Standard @FF C5 0.8 nozzle", + "sub_path": "process/0.4mm Standard @FF C5 0.8 nozzle.json" } ], "filament_list": [ @@ -2448,6 +2492,310 @@ { "name": "Flashforge PLA Silk @FF AD5M 0.25 nozzle", "sub_path": "filament/Flashforge PLA Silk @FF AD5M 0.25 nozzle.json" + }, + { + "name": "Flashforge ABS Basic @FF C5", + "sub_path": "filament/Flashforge ABS Basic @FF C5.json" + }, + { + "name": "Flashforge ABS-GF @FF C5", + "sub_path": "filament/Flashforge ABS-GF @FF C5.json" + }, + { + "name": "Flashforge ASA Basic @FF C5", + "sub_path": "filament/Flashforge ASA Basic @FF C5.json" + }, + { + "name": "Flashforge ASA-CF @FF C5", + "sub_path": "filament/Flashforge ASA-CF @FF C5.json" + }, + { + "name": "Flashforge ASA-GF @FF C5", + "sub_path": "filament/Flashforge ASA-GF @FF C5.json" + }, + { + "name": "Flashforge HIPS @FF C5", + "sub_path": "filament/Flashforge HIPS @FF C5.json" + }, + { + "name": "Flashforge HS PETG @FF C5", + "sub_path": "filament/Flashforge HS PETG @FF C5.json" + }, + { + "name": "Flashforge HS PLA @FF C5", + "sub_path": "filament/Flashforge HS PLA @FF C5.json" + }, + { + "name": "Flashforge PA-CF @FF C5", + "sub_path": "filament/Flashforge PA-CF @FF C5.json" + }, + { + "name": "Flashforge PAHT-CF @FF C5", + "sub_path": "filament/Flashforge PAHT-CF @FF C5.json" + }, + { + "name": "Flashforge PET-CF @FF C5", + "sub_path": "filament/Flashforge PET-CF @FF C5.json" + }, + { + "name": "Flashforge PETG Pro @FF C5", + "sub_path": "filament/Flashforge PETG Pro @FF C5.json" + }, + { + "name": "Flashforge PETG Transparent @FF C5", + "sub_path": "filament/Flashforge PETG Transparent @FF C5.json" + }, + { + "name": "Flashforge PETG-CF @FF C5", + "sub_path": "filament/Flashforge PETG-CF @FF C5.json" + }, + { + "name": "Flashforge PLA Matte @FF C5", + "sub_path": "filament/Flashforge PLA Matte @FF C5.json" + }, + { + "name": "Flashforge PLA Metal @FF C5", + "sub_path": "filament/Flashforge PLA Metal @FF C5.json" + }, + { + "name": "Flashforge PLA Pro @FF C5", + "sub_path": "filament/Flashforge PLA Pro @FF C5.json" + }, + { + "name": "Flashforge PLA Basic @FF C5", + "sub_path": "filament/Flashforge PLA Basic @FF C5.json" + }, + { + "name": "Flashforge PLA Color Change @FF C5", + "sub_path": "filament/Flashforge PLA Color Change @FF C5.json" + }, + { + "name": "Flashforge PLA Galaxy @FF C5", + "sub_path": "filament/Flashforge PLA Galaxy @FF C5.json" + }, + { + "name": "Flashforge PLA Luminous @FF C5", + "sub_path": "filament/Flashforge PLA Luminous @FF C5.json" + }, + { + "name": "Flashforge PLA Silk @FF C5", + "sub_path": "filament/Flashforge PLA Silk @FF C5.json" + }, + { + "name": "Flashforge PLA-CF @FF C5", + "sub_path": "filament/Flashforge PLA-CF @FF C5.json" + }, + { + "name": "Flashforge PPA-CF @FF C5", + "sub_path": "filament/Flashforge PPA-CF @FF C5.json" + }, + { + "name": "Flashforge PPS-CF @FF C5", + "sub_path": "filament/Flashforge PPS-CF @FF C5.json" + }, + { + "name": "Flashforge PVA @FF C5", + "sub_path": "filament/Flashforge PVA @FF C5.json" + }, + { + "name": "Flashforge TPU-64D @FF C5", + "sub_path": "filament/Flashforge TPU-64D @FF C5.json" + }, + { + "name": "Flashforge TPU-90A @FF C5", + "sub_path": "filament/Flashforge TPU-90A @FF C5.json" + }, + { + "name": "Flashforge TPU-95A @FF C5", + "sub_path": "filament/Flashforge TPU-95A @FF C5.json" + }, + { + "name": "FusRock PAHT-CF @FF C5", + "sub_path": "filament/FusRock PAHT-CF @FF C5.json" + }, + { + "name": "FusRock S-Multi @FF C5", + "sub_path": "filament/FusRock S-Multi @FF C5.json" + }, + { + "name": "FusRock S-PAHT @FF C5", + "sub_path": "filament/FusRock S-PAHT @FF C5.json" + }, + { + "name": "Generic BVOH @FF C5", + "sub_path": "filament/Generic BVOH @FF C5.json" + }, + { + "name": "Generic PLA @FF C5", + "sub_path": "filament/Generic PLA @FF C5.json" + }, + { + "name": "Generic PLA Silk @FF C5", + "sub_path": "filament/Generic PLA Silk @FF C5.json" + }, + { + "name": "Generic TPU-64D @FF C5", + "sub_path": "filament/Generic TPU-64D @FF C5.json" + }, + { + "name": "Generic TPU-90A @FF C5", + "sub_path": "filament/Generic TPU-90A @FF C5.json" + }, + { + "name": "Generic TPU-95A @FF C5", + "sub_path": "filament/Generic TPU-95A @FF C5.json" + }, + { + "name": "Flashforge ABS Basic @FF C5P", + "sub_path": "filament/Flashforge ABS Basic @FF C5P.json" + }, + { + "name": "Flashforge ABS-GF @FF C5P", + "sub_path": "filament/Flashforge ABS-GF @FF C5P.json" + }, + { + "name": "Flashforge ASA Basic @FF C5P", + "sub_path": "filament/Flashforge ASA Basic @FF C5P.json" + }, + { + "name": "Flashforge ASA-CF @FF C5P", + "sub_path": "filament/Flashforge ASA-CF @FF C5P.json" + }, + { + "name": "Flashforge ASA-GF @FF C5P", + "sub_path": "filament/Flashforge ASA-GF @FF C5P.json" + }, + { + "name": "Flashforge HIPS @FF C5P", + "sub_path": "filament/Flashforge HIPS @FF C5P.json" + }, + { + "name": "Flashforge HS PETG @FF C5P", + "sub_path": "filament/Flashforge HS PETG @FF C5P.json" + }, + { + "name": "Flashforge HS PLA @FF C5P", + "sub_path": "filament/Flashforge HS PLA @FF C5P.json" + }, + { + "name": "Flashforge PA-CF @FF C5P", + "sub_path": "filament/Flashforge PA-CF @FF C5P.json" + }, + { + "name": "Flashforge PAHT-CF @FF C5P", + "sub_path": "filament/Flashforge PAHT-CF @FF C5P.json" + }, + { + "name": "Flashforge PET-CF @FF C5P", + "sub_path": "filament/Flashforge PET-CF @FF C5P.json" + }, + { + "name": "Flashforge PETG Pro @FF C5P", + "sub_path": "filament/Flashforge PETG Pro @FF C5P.json" + }, + { + "name": "Flashforge PETG Transparent @FF C5P", + "sub_path": "filament/Flashforge PETG Transparent @FF C5P.json" + }, + { + "name": "Flashforge PETG-CF @FF C5P", + "sub_path": "filament/Flashforge PETG-CF @FF C5P.json" + }, + { + "name": "Flashforge PLA Matte @FF C5P", + "sub_path": "filament/Flashforge PLA Matte @FF C5P.json" + }, + { + "name": "Flashforge PLA Metal @FF C5P", + "sub_path": "filament/Flashforge PLA Metal @FF C5P.json" + }, + { + "name": "Flashforge PLA Pro @FF C5P", + "sub_path": "filament/Flashforge PLA Pro @FF C5P.json" + }, + { + "name": "Flashforge PLA Basic @FF C5P", + "sub_path": "filament/Flashforge PLA Basic @FF C5P.json" + }, + { + "name": "Flashforge PLA Color Change @FF C5P", + "sub_path": "filament/Flashforge PLA Color Change @FF C5P.json" + }, + { + "name": "Flashforge PLA Galaxy @FF C5P", + "sub_path": "filament/Flashforge PLA Galaxy @FF C5P.json" + }, + { + "name": "Flashforge PLA Luminous @FF C5P", + "sub_path": "filament/Flashforge PLA Luminous @FF C5P.json" + }, + { + "name": "Flashforge PLA Silk @FF C5P", + "sub_path": "filament/Flashforge PLA Silk @FF C5P.json" + }, + { + "name": "Flashforge PLA-CF @FF C5P", + "sub_path": "filament/Flashforge PLA-CF @FF C5P.json" + }, + { + "name": "Flashforge PPA-CF @FF C5P", + "sub_path": "filament/Flashforge PPA-CF @FF C5P.json" + }, + { + "name": "Flashforge PPS-CF @FF C5P", + "sub_path": "filament/Flashforge PPS-CF @FF C5P.json" + }, + { + "name": "Flashforge PVA @FF C5P", + "sub_path": "filament/Flashforge PVA @FF C5P.json" + }, + { + "name": "Flashforge TPU-64D @FF C5P", + "sub_path": "filament/Flashforge TPU-64D @FF C5P.json" + }, + { + "name": "Flashforge TPU-90A @FF C5P", + "sub_path": "filament/Flashforge TPU-90A @FF C5P.json" + }, + { + "name": "Flashforge TPU-95A @FF C5P", + "sub_path": "filament/Flashforge TPU-95A @FF C5P.json" + }, + { + "name": "FusRock PAHT-CF @FF C5P", + "sub_path": "filament/FusRock PAHT-CF @FF C5P.json" + }, + { + "name": "FusRock S-Multi @FF C5P", + "sub_path": "filament/FusRock S-Multi @FF C5P.json" + }, + { + "name": "FusRock S-PAHT @FF C5P", + "sub_path": "filament/FusRock S-PAHT @FF C5P.json" + }, + { + "name": "Generic BVOH @FF C5P", + "sub_path": "filament/Generic BVOH @FF C5P.json" + }, + { + "name": "Generic PLA @FF C5P", + "sub_path": "filament/Generic PLA @FF C5P.json" + }, + { + "name": "Generic PLA Silk @FF C5P", + "sub_path": "filament/Generic PLA Silk @FF C5P.json" + }, + { + "name": "Generic TPU-64D @FF C5P", + "sub_path": "filament/Generic TPU-64D @FF C5P.json" + }, + { + "name": "Generic TPU-90A @FF C5P", + "sub_path": "filament/Generic TPU-90A @FF C5P.json" + }, + { + "name": "Generic TPU-95A @FF C5P", + "sub_path": "filament/Generic TPU-95A @FF C5P.json" } ], "machine_list": [ @@ -2622,6 +2970,30 @@ { "name": "Flashforge Guider4 Pro 0.8 HF nozzle", "sub_path": "machine/Flashforge Guider4 Pro 0.8 HF nozzle.json" + }, + { + "name": "Flashforge Creator 5 0.4 nozzle", + "sub_path": "machine/Flashforge Creator 5 0.4 nozzle.json" + }, + { + "name": "Flashforge Creator 5 0.6 nozzle", + "sub_path": "machine/Flashforge Creator 5 0.6 nozzle.json" + }, + { + "name": "Flashforge Creator 5 0.8 nozzle", + "sub_path": "machine/Flashforge Creator 5 0.8 nozzle.json" + }, + { + "name": "Flashforge Creator 5 Pro 0.4 nozzle", + "sub_path": "machine/Flashforge Creator 5 Pro 0.4 nozzle.json" + }, + { + "name": "Flashforge Creator 5 Pro 0.6 nozzle", + "sub_path": "machine/Flashforge Creator 5 Pro 0.6 nozzle.json" + }, + { + "name": "Flashforge Creator 5 Pro 0.8 nozzle", + "sub_path": "machine/Flashforge Creator 5 Pro 0.8 nozzle.json" } ] } diff --git a/resources/profiles/Flashforge/Flashforge Creator 5 Pro_cover.png b/resources/profiles/Flashforge/Flashforge Creator 5 Pro_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..b4003a61a536bbb6247484807f047a26c9cedf62 GIT binary patch literal 106000 zcmb4r^wkQwt%3l-+ zV_cg0w#Eds1`PUP@n7SKJTwJf%3Pgw$VEPuK8mmAmqw8q+LZuz`Yy$fvyi4AQaBv{ z?s~+Uz+M0Mw_u!N#_j(eVf;)OB9d=>}^Cu#N+1Hc%E6{ z-PN(XNWt3AQaRs~4Xo$^x~x$~rgW^=OkFI%nk&2ofg1Q_iAT&6>5{En5ou+tAX*5j z0JRma1&n@_7b*oMb9&2w@{u^-BhmsQ1$oOLS%}>B?!Z9!6-Mx2fGpWTqeG|#s+gmj zgp$xuk7V{yXf)j#9D@#QkVU6J2$lM=@115%4hr?4#YKzKB9;Xq&GRF8qG=(iNb>OF z!2}OHMb>ayi7X@t`Sp}agE&kxe#kP679zpQF$~>2G0iP=FoDoHI2&ZqL%;|^z2O`~ zAw-)S{z@^w1hMQe)r$hW6Hz^@DnAr`cG8vnXYush!xF6MbTa20GkR;BMMhBY?w{Cp zVuP%3w`e$_W2Z4E@OfB1?h0!urXkzaAb?F$FhI>R8 z6lfJ^m<#6p93NM?aCsQ-xehUFbKjh>Z6pV+{Qc9|y6dR)O8D90yi_z_e*1`9ilkUHImsOkDqqibj#Y7~oc*K-#6$5F= zF$b+Pn@=VhPmL+%2)#74Jh=)9G-ROp5q61*^_&#ambK^-5cGAz7Sv}+7OXM?3T!B2uF z#qJYWvd~)Rp>*4{)&+#{ka0_VFoz)E@KNoTiV*i@KmlkA4< z)7l=sAraxFCm6|=C-I-N;MM4pg6y6WaQqu2v7|rW7AH6CH=7sxUq}EZsD|#nt_mWA9jzWmMaC z{gm91b0$(gTJgfEmf1?UpGAiGFD(+cD;U4UWqJ7aunTh-hA4cQ@VNQ-@YoyjSogq) z5g|65&hxOw^?m8il0!@AQjL4p~ZGUZ~n8)^o?x<3>Njy?wdR-khRU ze(|}dC#A#Zuv8po35TuxPRd&W`)+3H^}_Wcrw@wSoa4olZ^p{>Wl=zeZ?qHjlu!^L zb%mv-r0;*#&Lo<~e`mNxaLW{0=O~v!1|$+O!`Vl9U}rqA#MH9NbT{>i4B}B?A4l07 z2WwtbbOw8DR9Xm2j_T}SMl&M|QZYVL-4Mk2+)+j%y)@s%$vsFImYy{%WD7d32~9d_tDX!L{L zLj-1YYpKeOoy%&U2eQI#i}}GwVUYrARn_ErV@{|%kz_7iqEx=Hhi>KZ$LRhIt)^>| zvBEWj-f`jW-uNu-Pnr0aY}!{;piX_Cq@Ph=-tLkRK51XXJ6P&U2=F<4KSN{QR3D~Q zu4-lLgU{7<$J>39Sw|aBFY0>)nxCJih0gKfedfmHp-95re}yx_48+Aaki@LtdX`Vw z%d-vz*7qju%^YXe-Qm4u=yPuyw5%Tt6qL=~jQ#S(_3**O720|Jk&8}AQ?_;g2^;q? zn-GD}kQG%icy4%&F4uwPNCUyfIi_Vpc<0;_bANAiwOyL>W8V`*2wKq}L;9XK&$w=W z$I0QUkV@h+Es^152d8lh5LlxH;Y{ZpTNbo07SbvuCoOMRE86F4@yj(%PiA^?aSCJF zN%Xl#o86!2!G(oiE$oMqzF+bb9N4StN#^RjVcR+-SN<)-$01*mwmYHzJ40q#A7kR# z7pyQkoq;~M{Zn0PNsd->{<1~Fbh=1-T(rQWz5w5|BNYF86u529xXtXJKSOQecOvbJ zwcN7yTexwZv_}j6V4btLU;GkQk;(_8=S6ZqyKR;h9OT)!C@TSd+Jb2J2|5VKHL(1QW!+b<|-gC7vD44k)>`i%9sI{8MTqxWt0GeKA@%4+@M!!=9nc~bn~b) zT5f@X?e_NeKB{rKPh+abX0lCVug@9Bw*NifWkc%yeJQi;t3SpK?cj?JMVub^NHJNa zSFA<}iZ&mHJ!#18eoNGDMz%}}G@L<&CvO65@x1sw`WK|RdSF1!-*-CW7!RZ*P7N2* z8NX`kG`lD>zbCNqV1kCpvl7rvL+(`qj}y!Ymr+nyAd~DP?)BVv#1t9os+M^0Zd}ZI z9mm_TVgXH6x`(-FB04Ktztuh(a4~}fRC6>;&9#c-6Aln>DkW#!oL%;r6i_Ha;=>Wc z7FE8|C7XtxR(k-3-P_6`*pf)Rx_@W4FdKZf!g#FLVmKcrPs=e2qs!&+ z^x&bLnC4Pj#(Zh#VKFYA)W+}}UBPWaDnq4KLq<7vVu!#}`_6D8ISI4ss?5a%xA6jZ zDsjV)T+&I_UvVM{84SW1(vy_TP{zg8NaW=tHAL_5*UiBP2c8LTu`(yZL}AK5TWJ!!z8bT+Ah zkMt)L@JW6ZUjLH&-r@}ik0io8m*i24c@Zu1Bk#-?Z(~?z?6heQn;NGpSUU#^Uk3u6 zHp847Ch_z|M&niUawh2mT?r74kPq;59Eg!QR9$^%xytDi14IH9Tk-sfa}$Er{_;dR za7=huX<2kiZfh-#2Y0m04N&y>`k+h7ID9aT&g@)ApRKDG?Ki@FUfu9gIgTRY#rGA; zp7&eMy^^{s(R8zaOXKQ)F5rCnB2n)z5DZo^M9tH4z17ay+wgPygz(+$Hb5k0{{*wr z@gdc75rga7dK05HHfP>F{iqhwB#1HIprz!Q(Tbf1QR9g;GDa{vl8p(Sm40=zjhtVx z6OTi|jM)zBMkJi6!~*x7ziX$?)UDx2(?hluL_ zVK;WEko=Ui_*v$s9E|P$mtXaeXi3 z$-&r652jp#pTlb{+>J!*Pe0PzH#OdNO^4N`>-1SXdXLpbKQ-~oXs5p0#1ooqr%aCe z&~(;?ve7X%ZD!wpLzOVoFHR2x=F>2bb*q^H(YI1$Pr=%Q-^#*=X6$Xr5kn}7aSa1MOswP1>IjEkKXhr)v#@`Xz#1!#_JfzcW0NG*#y08g$K+)gv_S17%= z#IZg9Ev=gSA;u;(T-@soj1ASMfRD;Eyd%7R8B=k5fj_zfvHKw9ExXCS$(lX%v1+kv zZL{p~g`ob^(!V1=``g`@SIahbGZ3T5_gMyeBdyxh`ZrJZ@4c(${T7WJF815&%!Cn{ z(?M*(QV#TcBAn&lyGk~`qukfU92Q*Ku~0QnvJ)kSz{2aP8viKE(44vPaC|}s*3?9j z_a>L)X>>UZbJSxsM|ymuGrp>0`0q9&Er?&BqexwGXMsds_7&s$!QziWv|!QPP>)c^ z!H7ZkP1Y-OD6Lguu0Uu@#hc|&6(VtqT<`*X4&mDVrM%VhcL51$g|?D-M=3woqt}t= zuw(0ci8qU1u9H!}$4z_f+q}&i=0xh0&S*T|jKMn9+p1?q*ODoYFtCwAv`X3XQy)?h z)@ubPv!;8S-KIdJFM#gHuf)*K(&(N^B6C8RS%SSeVo+kiwZ!a3 zw_sX8CuEOmZCB_SSzm_J^Ea=a*r-f)m^mpV&38L>M+?7gdAX;)R+7+bEpCIOqvQaEf5cKcvcg*4oOvD{yX-kCom_qgDA`{S3VW1wDg%kY7wq}@BU4Hm*zJu?vGhHhL((bK5v^nzt09l9UdUp8_+Vb_rS-zo-Dx|g-Oc-6 zC&D!`GH0|PCdPQ>Ay76ObC)o{UBM>M>vDWiRDi|LH-)Ch@*ahiV+-^Cf zaFlS;=Q*@Veds3Kl{(ZN&f>s6>ulu?4Nxs2Z>CJ;S2O)I3=Iq>e6Qd2z2>`zE25I2 z%$Y?%D^faP(Iv&jOwhjcwO99K^=5f}^(QJlmXG$R2w1qpYmN-W7y8|e-IrgE?j)X< z)X{ARe7FPYZ0mX9M#Ua|CZYekv7lr4y(}$cd?sp7aiG1%a@y$wLip>HUQ+yQ7Q%1S z<-FllySIF_H?#9=2)5-ec|>V@<;+XC(KzS*6Gw8K7^Dx0oW~v0eRCzRE4~R=UX?pD z9f!`M*8^5O*{?@7T1IT$0K;G(fx5a!iGBx}MSO~x{b_oIC=s@L%&O)=QQ1K3WPTNi z1TCKL%rQA5bB6l(KqjRKKYmGOJBbxWK#B>$-*mo2WJRg3K>G^xaUB zCh&7i6!t&h^)G7c77K#ECO?mwFRfH;F>*cEyv?G?H_-BpODPRXmsNPXFuWd$7#SX) z81RoKi7bG}M=P?ff+}Oo6Q5yQy>5f#QT+fVSZmIXDK!UFyPI*@=^Qvhz~SafD~Zpz zG+(kke`>ocWJ@*p^ieZ3?Ql*@4GTtnc#&JyKvGjV_#~j-WMqYesw%Q9=Whf4^1}yr zO{hYm6TwK`+nHh72cGYD#|;G&e^<)CZc+VhR1+)^WE{wx0K=2r+v+I%bqBKJA`+9E z+!cQ9+Cfk*D>~3yNdO3!^;oeEq4LqIedZ!S8lQWy@UR(tuSmY2si}QqSKJ2%eUw1( zre!c5nAaQAst{(TM)48QgknezBpUh_{sZg~5lmGHXe0s4lOb}qj|p7)X1agXsK`!d zwuXgid|nGql^PyWk&w7(492?^Je&LC!Xt2*WnlC2^zfoN@_lcS#}f;#`r4nUzvR2W zpyi^`MbuZOV^Lbx|6VOIJayQ_p7`CX{|nbem+&6eSfBAKD)J!c)xxzFrj42{x~sO} zOHu%^h@I3GS1zE%y5ln4@LRbPU~uz;rLW5%^*!oTM(qoO0iLb-Kc z#iGfUPoY?C7XEw{WFr3G;VI;otQdmXu{>E_^LU*fQICrvkW$zxsJt4wNf*9L^C(P{ z9;*{;5mw>1{VIb%rI!IDAq@8*(ux{ZbWasdZnuJNw0k@2ztl+R2}!TCpL_Sz(R`72 zX21sJ4Mw%|`Pkga_kj=BpG_sxS0#TB3~Ud6oo>6Xtz5>#B9pNG7OTBB133@Rp}dR3 z14AO97EoGT`cw(uq{jTPdS$BTo4BGAN??d2G&0sc6kr!oQ42j@`^9haqEu5!bM*MY zf1BQxZEzh{GdB5Z`!%BF^P~~IgwQrKDE^$OTA0BGs$*I46sa>!J_b6<$F<}5g_Xj{ zO0T6~#>-~+uS22t1404mRo*e0t#7!R(Z81*hxv3=yc4#am-CSN;e$5#Ae=kjQnxI zgGv#|qV#iPfY{R+hncPN^Qo)?dHZ+`%~Vhh5PYHSpO-KkKunTF>!a$S>beTIX>nmWBrk!E7OM>g9ZhG#jPY28M;PtLkAk zhWa%BZKb@2e#L40IH!`9(j=XBJ`72vd!y2f!Vl@RJeAz9MQS%Yets*e@(tVc;$R6r zl}?5c5{sUme?-f_pjO=NTF4vu6WT0GA+%pKvVpbAc8(!@-8xl*!A%!s)-TvuuQR5LpSs)*0Ud>H*ZB~t9AWG|l(l-uJtVVpY=QY!C2o7bj3azso zerWQ38Qnh~z2@D<^Q-Qy$|clVJp9okk&Or%CYBwm!B%9rSkoTBeD}liVS$f}0t|`o zTutPmqNZLuSbX7owSvNwULT*pnd0~DFxA79;bqzv&uf9$lz5L-Cspb9v5&k4mLhp; z$E72!!RLIq(bD-Ze5kp)uL!?<@sWV^d5XNsvU!M2OukfpTxyHPp#vvw#;&QB{7h%_ z(WDA;Qn(S3RQfRkl_x-ufLNY@5NVBL45G4y=%%wHaqH&0Y=pUD`*s)yoy+i8OG`0<;W=(k*^GYra3oc@~)-cdW5~Rp_l4y~}>2|b%b#Zy==I);O zA$8E8Fv2aF8<#+q$N!!>dVrw4fb%_E3P>bshgy7+95=Bn!~xM8asS6?BhS}nm;&@!Re^_qM> zH@v4*1b>A;N(O)JL#TUpgsku^x+;WHZgF>=z>75Sp%}>pb8llQ}xMW zGZ7cJzkgldO~H6tB^|{Z}rB>W&PI@wQ7M#(yD9hgL$ZPIVQ!|L$!PX0t@YZ za)2gL@nFx!QD(AIF4xLW9PvHbCMZkCdd~u;Bba39E9hu(yS)%Q_|s_t^6gl($HEcTlSzj>t9RsHdo)`L!R>Gh|?w@}?zHTH*l%lImh z+E14~2q=Ub=*xmJst?$ME8kwoBPE80|MpICbMUX4^Qx0-)crcCE75N2&=6Ah5`9nN ztNBxafbb18vN(fQMGM&Jg$@t0%Y(%}U(r`tNPy@naK@}NzDDIV^+yRP_x`zm9%*Ip zmR^Z(3`sQf)%|FgD4L&k`yv3A^a>QpufkKP?CR+m%bY^9dR!_8OBn%*f`(B4RJqzw zOUSKBr|Twm_sz6;Z>3hbtE(?$`1>poB5Gx5hYW#TZa|N!=7y&pP8+WrT;V?5e~J&R ziI%#zh^x9Ee@z45_jRZCh-5Y`@Q0m0!KDDjeejc0Ky4td;ElE@)**8#%@UypMQ4V=RLs{Q|-q(V7vXHU6 zT#E8DZ^R-|wgHSea=c3CywDm}u15V#fe_UDdyDkq;==WK5~tO56_q#3Labo@YU4wA z>BSQf4Iu@aEDu_xREb1sNZ;=*CU5UAZaXK|qCq#rDbx!i1DN=3zP_O>@e(XU=Z-V3 zfq{u!K|4;y?VjWbo2a8hlQ+Mo8_}Mp3x-8-<0;C1oncq#bJvB>pV0Rv9_EDplxCm)g3kVEuf}bdM?kd;lts6q$^ia5bJgqd29;}#+DET&O>R`61whNK( z(r7^p1d(8Mz@D75-8z_{Op@2AiZJcob(J!+<`Wj<9w9!77`j}*FP^ztIf9!jSL|xE zh$1$Bgw7OiW9rH77cS{pCv7%4abzrt#Y>GLfzXdH9Y71bJC@5)Ee9mSNNC{d^vuyF z*CSs0y;#;MdU6WB(^7fAdL6IqjANfLaNvndFi=#B<_6jtZR?F0W|w>7@Wp&-(vQId zt5D_<=BxRhYfjVaezK$6o<~gDm+?b^rgjA%u2n9SCF8zEA;_h3ZTofc@rFGW zMJnYe$sf6}gfjl3hU7;&in`S5c-+5RD@tDM11y7qVscrwK-CZvyWX(+U=PTc_03&T z%lC_QYimOZITN;U-|l^f}gbg=qx@ zT&>(+eh%3q1$5XD?q24iz{EeE(IF?ykHi)*b5ZJnh9(lFZzy2NP*J4(6mC9Gj)33! zkh6tKv6qFh^a?lQYeiN&Xk0_Ta57Jsm|_;6Q_u5!FI~&7#lcdB@Pqvvh5819jVz>A z_DmClNS||VLeGK_UQ4a9v2?wpAb}E1a@NMSKL45v-nMd_5w)PWD`wx9;p|5;ABth2 zT(+`d1_$o~MTLF73R2x#g?BHLN&5^d0)<(Q6_Kb)s8U!qQ><`I>V=*ZeDOPw0-%j1 zlbQKrJ^r0|K<6~=j9p)U#-61_@+i4#v3f8(Cxq7gWtRzEjuE1L{7fYaE+R5GY=^dd z^V{bL)9e;wO%?O>4=!ctlZBoT{N?+-9+}(^voNO|E}@vU4J?!fev&a|7;SQUY^naA zsW=2y%dr`N4zYrsgn@=@Y5N6pFE|Zj8U4}-J}fA`98`#j|FFVVcNlgz=e+xX-yC{N$JdRu zB+pca(7!#xey;>Ud4d+nPfWexFViTcO=jCG8+aCq5$>z;zEVEthp{#JNq^WIQR)c7 z@OvYn<3H1CbP@LYnLNnb&3PLBLfTn;0 z57=T4zFY4Z>FV$SsC>7>C6l|MqDQj8Q=^c`MXeWrI^tHSmu>R`A=_#|fuZ=6Ark$a zR}JI#9{68={2@M>zxfp>*{G^Nf*Y)$fBUNRI!|6Q4VWs>)@$P%qNf zl6UA{Ro+6$3sqVP$oQt^7Ga^vwsEJ)m-;p1?fUYU*f^gRxaxOj_xX1g65fsCmOlH% z@R4*=$084^&bF2-CmG3&o5~aI`Hpr}b8Hx>066Sh9%D!k27A;jB>ghb`?X^3=2A<=M?k&vp}b8;?khNI=nATTc;Z5ATh<8W6vuF!jH-rlO*v zALXOV>}bu@>GhB|Z4~`g_x2c%#2+1%yKsGb8w6wwATUDW4<8qo*KW=oVacy@RLZZG zF1r)N@25hdf7(SJe{22Q2(cpqqexVU9Aq)tM~$+>9M>O}d^7G%m*2-xy`Cy1w}pjs4EZ ztI*BJC*?sIdGy@2j(zUUy4~x?a4(I%K9#>u8e4a#qkIPtW*RL@PMXlj?Xz|WL^iif zeu|N_5v*38;s#{>fdT0;B;N;xcWYg<#BX>hI;bLr4Xehn z8th*}q-2%-+;mNE=7}Bma;0!4IR4A9?^;3JT3xAe@3VF%%PBoQ5iJc59>zn2VGfT3Xh7=Tx z(yxA3*Z;|I@l?}DfPH@ zjw#r8@)8RaEP6IR`IbzexL^M_*ooIcB!_Wt&pr0EJ-go$5Pkwr^OlDJOm-h|$xV@T zw7n{QH}2DuP#1D)1ZW@U>@vpK*zXA6ZIVMuiY4vf9sbgzUyc@}02EIJvoaUvn%@8M zfi(6gO>#P|91qvNkJE8CjGR(Uwn~R*-tma;2Q0o!yHX%ALbj=>W`Xe-mEzf^woe_N zih{c05!ls!yC*rP8o45djOZHCmMM?vIh5#Ia|TAabVVWYfz~~`Sg-+=g|V1HedHU2j_sC$F04z^ zw>S~6MG@gP;;jw!*mc|ENx>H&;JI&68`{fa$?IGmZLn>L``*3R^wdl4g80`p^jC|g z#b)jPPH!>-sV|3g+Bf*R*%-aGi(dj>bjEl4)yHeHveX59o=Z+@@!;6wV=VWqgw)bS zJpU%x9<|J?94ZJbUDA5vGl#){atlRxh9Ick9>YTa zwJh88NF*4fIbG&jUb)|r)k$s{)ATlCPYEe0_a(7yB`l1Zo&U0@ z`P;CoAWUam#C5&sak)Y^j;=&FM|6}`!`Kxe$ueXI2S6`?RF78rq(y`8Aed@J^rM6_ z8kmd0YNv;_MkjLg31 zim3}cufEzz2}$Ip|H>DQzjRCT>SUucRf{uN|4A)v z9v;KL+@9Vi@JChn2e`Be11r|%ri1RnU{D?bZK>0x-wNh-dovfi3&R#K@uVRL5Zr9~ z_6vT*{kyM3bmshzO$1>~ZnI{54h47g3SLM&+xI9Nnb|z7gQbpy>Z0IiIeeObjAJ}K zQ1Qz+7qJx0R%yoU(D_<-KgRAQd8({{=qyPf}`*~pNs<1xpvt0Q`=N?$f)jcp$ z&(x3Pw#9jMY4OGO`3-QO`*{uMi<^EN@IVQ(9AC+Xve7+~mCn_9<4g$uR~9C0^KHo8 zvnUDSGp}U`T&i8`-GhpsL~2t`6Ag4d#QtUjZwR42$x|y}GriUz=*@0(I!CF#tR6J( zF&punjm#)!Yx66Vog#L4pB?7txEbI(iIpDrOg*9xL<_z=SQ;uX3JedpJPhXps$9(Y z5-HpYpq1palmG-=Q{(ja?}4SyB{3pjIO(Sy8kIyYgZw0T>YG00*e{aV*jTJn)FN&O z)JFso0b!t(Csj%uu}WlSHupMyr@{b}%gjc}~ zQ2Y2O71PN0q;;6^=s)cJgGp5{ ze0s;1EUI*TGFrE?8i5)9$CfH#NHd2Jy9o6i8ht!{sN05L70qFcXN8kR5Wsu&pwqTF z7t9j==(oxwp=`S1W<^=36|D}N>gcpNH6YQo-?U=-Tgd)FcepPm(NDV;kks8Oj-Bfa zQX481aD8Ud1WnBx18{uQAKxF_S)s8{xFQiw3rou*<9R}T`pLmPDS)?glN>Oa_6mP# z@%bF&N7+$+;reig4rF=|)#)`V00R^a1Bc~C$R$vVXGp59uiu2l-~)m9&b&TnedP$0 zLi4h}%>!BA;zKbyM5sX=4v?|=pzw-snbZAjd!l4qqJs*nCR~kFcsD^CiL1xYEOc8v zZUw!)Wk|ntb-jG!;zT#DIkx5TnLUC_qWtLVrLggC@V@C6gJPvnh1GA5{h7~OgZJ4m zB0%4Gr5ASWyxr5BoCNdeCipx>Ot=w}zQU?Fd;fS4z0^EhuBjq!-FRIoov-SOTn{Fi z8NcMBPtSj31j-atoLcLypAU{!unl3*(--d z-dl5bnyYQS1=Ta z`k;~$fX#PUR^%s{X=`}4sULbkKmcR_+PH%Ybo{!9-$w^1S_jM85pKkQb;?q(Xmu;e zvDIsx38>tW3@QX*lr{J(;#VvAR)Tq!jscX5s$?;kYACM2H}yawN@otA#lK$*3`nFc zX1hc|emZI=Q?;_srB%^nun%V+C$3j&Bvxo3zW&Pk&k8$v?zWc5P`>*Ai1%snM?A0-?*9D4(7C_mtX|^%OCgg&kTIBEWi`l|Y1^ z$oC^OoTMD*I}v}8+0=BuIQ73pmYnMyM30wY2aFtc>CM4GykAO5t9!F@yA!-3=DYC4L?AgIJUZP zV#DD;hpEpQC|daBc?1y}q|Y39ZR{J%!>&hG=jHY&Apf}{e(rk{i~vsQc))?;TPX)% zn$DB&)%xsY`s`aP`Rht9A>?&E#~5!n32DR5xCxZg#DMQa9?55#^-MwQbtN2CsA!@- zXQE!25NP?7ZTU7TX|EIrekQBa-=V<9q;SaixzESwXPdH&CQL%NYfq*eHJg=o0-O0Olilrex#RT-h@&m7tk6bAyB00|jjj)A_k=dlkTfKY(B z&F$jO4?vQVKQszjaD-4%uMFTX{mb{R4wuBH!RI>0a37R}D08^OvnGR-rDG}qU^8czmWHEn zvX72OXy}vaHDXXKlA@D#9fLLP@v&iacyK){lT= zRB@`lYSHl5g>Eg*d&}~zH}tLN`oF%ooG_fO=wGb6Fc)O%?oCdG6eRTX;rvpW=&xa{ zz+qT-=m(qvL)({_t-6STI^37C=x9)V5&P>sahiR(2bmu*DTD zi01vu$BPu5tT7p?Q(={iRCMvdwn0ZG#J^1wvY{|egphd7e(&6_uXMQEnhWT;dwR%;bd5+-)N4S1JAgFH73@5kOnq#$~KAD5B`7)3UOAB?G0f10^V zqo29%yeb^_&k?t+`kcOLvw>mhy8_<#I97T zTLeI%IJZ2X%wqbFPSEQ(N@Fk|1kI>rx)-75-;UcUdX_YcoeJ$;IE`^8P7b5Nti#H!(2193zj z6!3uqlqwi5j2`#`6B^$lpn{=A9)ISkPNl)w#`1#A_+=fbP= z?&SGOzD1zBX4>`}(fbFKve)0>BX<1#mSO{!Avaoom)o&G+vgY{z#oYLUHP{Rj(`h% zDxkbxIV%TI25jeqn>t~K=ma33M6yrtz;J&aUZ#~-cI7IHaOG_7Ht22*TQfdSfuh(_ zHD05F!9Wbdn|-i7i&p*xQAbCB?`cho>uNvx-@`+|l{OD6%4aFt0aU-My`G0U-@O{H zwSOg0p+VaQ{jsrH^_7tsXZZf#zlHrtc|tO>Qcx)U+9DD+1EV-&HaAmO%IrC?r0u9_ zA+fPr+R)?4+X9lF#X)uN)jMO#q~U7G(#5M8kmcQpdgA-9Wzgq5*hjA3iXS^Z*b~Hjs^6 zdhTDqoDyA+HWcbFIHlXlUQ}wJDG}!LMF;m_hOTv82FIm{-#~z&x`Ce%c3YtGY@hr8 z!vROblrHA{6l>d86`#?FFsJMqssV9EEYDI@OcM60m|y!`)TR7JC)-2)W1N>Rq3-^! zm9Vhz@Y0g~-M69#*5He&q7^dW2$FG%_LBjrX32jq0hT2APxfJ&!t!6_`~u8i0G-?& zFjdpDx(96WKcL|5&ah=n_tz9*oXaP_bH=0>qmDi7&YtC=?_!vjVa@TM!+FvJ2I>{| z<@696r7&j9lps(*$RjkRLAk$vN!+)cVwWxXYYsgx=Ddyx$uAR80bkDuXXAbPf>)i_ z{n92TdMT&=&_Ab|;`^Ymbj!Rf415L1aCEi77nShcX&Q485^v=4?d~A}4SSMyJfqXs z*C*9VZA_(V_Np12w-T-36!Zp6SF89B82AUva^=q(sy7Xy{{#XD1hG~fa)b$QZcI4# z4UdR;_9GPgEh}>4Y>BLjOp%pz6g>+7Ev}X3?u;&4{vJvvrt~I7u+PF5mgmfL#6Xv- zLA;joc%^n!ZFY|x@;Gp~zB&+dwOAKO@{iE~dRy21U0dI?D*_g}e_-d^G0#Iw&lT6z zjZk+Su-E8vF)?et=Q zb0d_3VuZ1kOVWnF;$D5t7~%hw$&}Xke3jZ*=gjA4Xit}%=={%|GLKc`%0Jd^a+%I> zNqcLFXZ0>3K8TVO;{n%SaOU5Yw~TndmV+vX>gcu#Oz|TgK;jR_%j>(gMgOp7mnl8~ zHvyP!wEXa_^LW?@uuk;9cMar==4Xzt;u(w~LsI2Y=9wELAKvf#93MTPCBAwVDH*#7 zcqS~v$m%*{5ATkP%zx3WeoHTxpJcQv_7nZo8j$JWg=eWg>%gH=PRAB;!A0d*UD;p5 zGZ>I(LryK`A3I|j^7KDB4yZCmr8L1bF)^61&-}ohkh?&#)Oc=Q2=BeD%AEETFv)e|LH~#-QSz2EuMee3$*;6N^ z2u`?j4~yodhm7(tv>pME zjvakUl|AfFU})oBCjGC>F47=AfM!&uSUK#zY`NM+B^f@KuvYfWE8b2+aBjBuVL#|@+Uy?iwJ`&k4$$*~)Ca(bkh22u;XIchg3~|5 z39k(R)<#7s>6}83oGf%wq8^2pE^hvnvAg?0dNgBWv8mZ!ar^J|)9cJ{84x-Ee#rDJ z4}@ISJzxT)_TANCNN9@q17uM(5dhF@AG1w|clc}pdK{3ud&GNFLe8WEuO5ICx1>u~ zpofBor;e(~aw5vb5Qt}(ub?)C%TPRgIitA!A0s5qqO%j~8fXzsVOX_bFCn{NgCh!- zxtshHv0x_|ceY#mr)lqfT1ge&%t5JtPnfzt_^=@)#p~zpWNGqchSIkhnd0WDE>eZ%a-q5~loEV)*%}l;LrIwj>4(P1#Q?RqpC$-d zR6Ip6@{3KxNT>nN(pg;1&BMb32OxR|Q-ZJ1prA!(GIpRb&YGQD>YM2~c6#FkRKP2U z0m9thiwrl8dbtYZFH16pnG=D8OYyScb$O4Ph*96xR+x@yMp+}mt61sa#`qHt zanh&bIccY#d>L&+ueZ_`syOy;SPo|sY);si8c1#y;N8iXNYE46*`Fz5H^pDmU&_Fu zff($oTr|0B3As_@p~B-9Bd5$Qc36&1((S0Q8W0o`I^OtZb$5^7jSmfPodQPI<)?^k zRg3zBx*wjradsm9Ic+>O!@d&jA|cCG$DW{U3dVcwSBv=6A(3iQS?WE$a2RWo0lm#S zCtSD(Cr&_N~gDu0iDReuBDiwPum&qoq3&i<~*f5(p0qHuM2n{ z@&&>4nBr_%CV&49%RmSOhhczA`yf3x({)D)KFg8-a|1M7$HxR0s{5-&4~-$f)VUk4 zSY<^U<AC?;Lp$Yth0DgR3r)M>a2CAba1oOY1;GT~(DWBI;Dt7o4 zd^cO<;nF+8s&0JDZrOX`FsWUU+Cn|t$JN#68LdU)Gy#q|S!nNw7msj$SfK*cG1v25 z+pFt|;CR|Z?Kg+2EeUl&_j$lPJ@31Um1k7B5$4bOh`g!}p5%J~1H+xaX4qkT64~8AwI#f z8Tr9_|i_U$?~^jR1N1H&!-^H4@COd zN~cK;8+DjXPSsU8BP#6~wKu@2?Sg_0-ot;gW zQ*hyDKex`L<5_dW^N+&IonPht#Q`Pe$_eEdC;L!sd;2F~ER%oMDoe4UVq8*ReZK#Z zuBn7OM&#dzz(q1d4*Z7!+)7!yx~0j#ypnhk9F_f4mOMMFZZ8kY95{)X#URgl<;KP! z2j9nMGjogk&1?P62SRs`ca)LTVEJxcqH5KqJr`dW_ZQT^kLlkIIdb7Noo6^qjJqin zy@Auo2;A*3hd@M+wz~YD!#4<%tzZ6gg5iRMTo0$w76-ZX#*f*CnX7z=_U5slrRbdd z;Z=^%aHUDJ`YtMY+T>I78NA>5cv%WMqBujirt1WuJuU2CyVwQ8=PE@BwgG)X7@USP zXE*Wh841k5PqD0jcs!wUe}qedOgUR%QQQB$^lYm14|u2?Cx9a=SUHN2XHzY=@WQB& zR8hycni{u?xGS107L^V=z)x1y2va2?C*2-TufMoG^kh3hU-6pdB}}_ZGM(U+qtA-QV9Y;Z5qot(1r}N`jO7)yE4q`}LLpzEl4?5|Wa_z2bsILMzyBktST!u8YwGr!n~zjLhixWNW$ z;=mY?w0XPlB|#I==l4uli_1RSGe2P0Iih}l%FNOdUnheSjoRnB*ZaBLa&1pu>+vy0 z=;72sDQzj>!|0EcSeM&Bf`CS)I7Kj1DK8F>pd7qRChaTCEan2Xh!F> zmI-9|j ztikjLA!)P+_-8G5WkoOTU1>#?6Iu;t7iXO3ON58ThR@$m+(b~n&Hc~w%gPBQ@(H}b z_2#&XK@z&9*SSrq(=~PoLW94(HTU8KuX_o*&- zmC-G8?jD%?ZyZ>{*e-w9y!eTz?7LQ^ZWm^A6HtX%V@B|MGtQ2N@@kt*p!5hN-Z zJ#hBA@(d!8cf?XaEwiqKh86?SFM0tYQ;nZ*!=tD#qNMLHE+<2Kkr2%r-+fX z=m5tA=#Bw;4UmP87OS@xCWwJG(CVjiVua=33@;S8TLzqv3TH%+5d;dV?*M_~Ie{K( ztbNSY|Jm7U9|nmz+z0Dcb$NgbsXzllInVPSX+?#>RZRq$%DRNEw_@3A>h530AR-nQ zrIH+FJLCkF>wnWzYR$e7p!bp{pa~;%Dd1-nlbj0iaiTfdP#~-dy;Kemz9y$a)_f=u zs(`}k^SJUcm>p89&$haZF8N0OGfN2oA+$ItFz3N;GYmbit)U%`J_fN2Is&xN7RL)J zHiM2}@IW-OXus2+4x;LwmIDM#UoG%Xglve^Y#>okF_V#!QCW(K-GsH%?{?>iaNfQm z9c>=Y-c|?dsm~49sYs5>#`1D6`R}boV9R#A16_nm{4*e%A!Tvc{dclCzT`6E;*|3n z|Ew!$&^dx3hO!X}jkYdjBXd=nV2p$89qOyQ3SPg;5C2Q_!p-z`;E}(HM6=6sbS(If zizN)J6}!TuaFK84MtXiUdhSfb;-vv=7ZJx_o@U;t)t{PItyj9&*YR1tEowyqX{dTp zykofV#YfTU{H_xO?@uc1+XBTov;mZ5zA`uB^=J?*ke6V3&;Ir6Ti5HL>Y=o_^2+Dfwy}?vnFFB_CXbZY z5>CN?jA3MjhZB)g#t=-jEetDtrG>0jGqGl7arCAZlTO!^5~(2LGh48eMlJpTC_!W; zQuooDyxD$z;MdiDo%Up1XMHrV-1Oa%kv`uodmP!7OEH2G#iC?`nIz*rP!*l~b!(YB znGfbrvD;>EFQ9^tDn;3zCK#9@=a0p3lF3=}C4aC@as{f_r7nmV*kOIkVdSMJ=cshz z<(%`0aq`jXC>bXZdEB7im-Th3T3khu#NcpAK54VAdw z=l$M#XEq~Gz=76YT(lY2iL_z@A<+9v@7*wOGnX+8(9&UF494ydL~;DSE`1B|BqBA7 z!*)D_AR%!6KRMYPo?Dx?dPTp- zwX65?!U!r{1g>*WUNtK6uou#e@i)0Q0p$}4r5QtbNA^}M!vaz+t(G4ziA9pqL(UN6tCHkh9aaX(YN^8l0W%j^1spy z8l!AMd1T^dzWSvQ5}NE{d$NCo^z2-i=7CtFs#|_TMdE*-@Xa7M{dZ9%%3EwZw|42y zBL-}~k-D{mnjhms6J44W`mm;JJid??qMj;ehjDL17sQQFjo1ob3~tMr|7sTdhsi$% z1A|81#u>Fdw&UbQaq~y~>=tl<>Ts3uF^uLPIo77-iop-?fgaB3diN*qyHkJ@Gq;We z8>X6fDFEWI6QIYl;189>9Ir4d%=zU1)IC_pqETcg!r&ml=phi#paWIASVl2K?5(Jg zhKD&kx7N&3{OyYmV;aBtpsbR_QE%@d*42f(J~j=cI@^ zr=)&5Ipy|muZ(aSZl_gIk@9dSBYwIWkl=e>G$nZ-Eu7|HAq{ADFrx9I<;onIE{yY{ z*=wsqed01&$$4*lKR3kA9jEXRtG3n$9@t@DWk?BUd-e+z_3M*jDBgOr*PYxw`jU_d z{qqPZNf$|HPgr6;e0@MOVYRCE;fz$D|6aL<0er#aBa^@4-#L4S#~jzm{&9L4tC)? z@;?1f@LM)VXN5Em)isIGz(eyu@P(a^;u}gr5%~Codg#eNMy;up)^^qhDU~*4o^7OnOA;iI zA;r6U$Y$-AXfU-za_ac?2Dhs%m;?$Tg_x!qO`|@-FwByA%z};vWlitLZ!>Pn)DoEk zPm~gu%fcy`5gJWMf($WZ$=>w+snR>RZ8O&YF0%3b^4vdwc;dN*`;NV2le7n%2&tb0 zjt3BtFAnK*{W$=V0hCZ6$M&uCuC}o;deAiAt1&YsdJ=goFk{4#xziALq#lQunE1fG z&6ovg2kl*sFrIWrr1qJ!kL~FLQjz>wj&#j;_|nM2FNo+n3}Qs=%im#&akB04-+_I9P0(Y87)@?9oiD6Qn@v;{OF2@h2EIR-&9<58 zuJM0Ph)JCi37RCEm8kDr5QI8X-T& z{qcCz6y3Fa;xvlSkI<7~^VgivY;#1IH;L*197PfZgi62jwp>n80Ju5YT~I8ia{4_v zdA3uCeF;k9HOQirqWB&<$?VrVVs;YET-*Ajx*Hoqz3M>%7 zCvkhLgnxUE0K{TR63OptOOoA2h>@+{mfhEtGo}q;CJ-XX6~sh@KP>gdw`-Np%U)b9mXYFnW(HiM;qfNNUS-x z#;s8J;rH^xo=)hWys%F2m--qB1v;>h&u=I|F`|ia4>5g?Hjpm%)IqjWOgS{`scdG} zD6MBS^!r6?XKxP&lOyC81uQzpIqUrkw>%8A!0ZuA{&r|53=?>EL`5V<^d{piTaE9L zMWKix5iw~c*U6d%A^ZQT#ypqhB$VVfS5w%$L*+ppB?zpUeZ<0ypfD0Q)7j_yr}n}Q zSt^Z~)Sr%zIbgOXvMl+9AMUByhoF)i z!1ZS6x%EQdZ|j8u{kO>dFM_7I_*wE4Kbje09IuAlfUgpGy1=fvKbbu|v`1G^7F71! z?whn%`PNt;#43T$b1Q`T6+kTllNO+j0T0Lb^(E0}degR7ATrS93%Wnd zbjnrIGg{E#Vn&DJ*v}#RSpP2kA97#*@S;;KB@$5ZvWv!Vrw*h4L*rk;d&AV;fytXk zv^-~HP`F;DW|n#Ko;>CQdL|aHySx$Y$9P#gAzaqLHP@16s%$-0{ZkDRAV@sdd|SP0 zuHIBdHYC!Xzfg@tz9{r8RV4gkqF7L{@)Ki8MaIYxenAWCJT!fD^SrVtVF5I5kb}E_ z>9czCV@~|XuMPW>%8&P}3i&N{+HB8TOjQ+Yku{1OTY7`2`p4%mSL@r``2`nM28{2%X5feD15^iJv1h^Ib{HouUNNCJx} zvWhByK28G^A!SVRLjO}?jY4RQJ>%oQ%rQ=qhchJ;*jZ`s6eGRGM$H<3%8T6DI4BpZ zEiKgVI_g+AnyL7eRhBx~#eC>ky|i2X@!wk)v-KL8A#TH|hwLxO-mE{f{%FEZ`cveM zd_icwbAX3|lZ$7;*7rJmf1JJCZ^z>i**0V)d{_%xrBw6jIre#f4`hD|dEojv&09I5 zj1i9)8gVpdKvE?jl-eGx|4?%E^!`-^{nW!Ai!_dhdZB z-!_g+VZZQdzbRs=OYG+gD)X7@SBhI?v!_ zrj$3Jee_h%e)J|pbWb)IFnGs5$nU7Weu1vWOS-KPH{2pG&^jvcov*scUhAoSfBEF* z{9r~LIN0;P9U7<8eE&|c6}@P*7*l@Ok|tf=auF-7KqDm?KwJ!tj75i4k(3guaa$3r z5G(co_288Q=*H%mPzs39gYDjluxC!5hiG;CM@K6{p{uPf#P7h4(Ta)>K0~Zf zs_V0F^zWd9@iN`|KO!)#Da0gPPL72GW^XT~CR9T{I?_cT@Xg zZP3@W=wQosPfTE|(Sy!IfdT3I@HGKi7`Q3@xv0ul)TpK8(;D!?=#?Q6@{Q~dDwX7E zL<0ec?@Md&=x}j8xI^KB--YV&QbQ&e!x>D?wyPJ}Lo1WQLveaIWx*BI>EYVi?1W6n zlc6g+?gOFL#*s;#!9s}6;%=%j^3f2c;oMf4AD!%%0pN(<|8(F4aJY}ncXf?*5i?da zK32}5AcW{RsotVB={!i{I5g%Pa@B_v?Em>vwBdXe0D>2BAl&cy3d;GADMwK8t-nSu zie>ZpS1dFg!h0OaoqV<;J8VO=t1*^-EV(3N?_aA{Ug8eb`D$Q~MNIBkg~5C3A!tBC zMza0q=`mc8%Fi1b%IAGb0y5zHPYu!WGK~^2v$2 zHP_6iePC}`{x*%aI;cW9?`)D?Xy=Pnd(aIjr#Q0&KVoGoNh7G|ihZ?dAnsN zt2tA+9d1Ou_nUM!c|e`tt`Yt#8Hi{`F`w@TOefGV0!T z8==#pjT=8*Tq)KER}^km8(9K2%;zvfiLqzJ9$FIgCO&dS_sc{mX5#z_+j}h=A){At zBuEKpxb@z{ZX@iPI| zH`j@Lr)F5w+k3bFtGpxb8T>e9>5{d)(!aMyM_`twFy!g@7Z#`mL5AJ*a5T7<0uc`} zd<@9YVN#HA@BNNLqQabB^9;&V%y)IBmvn^asMkL9be)6s z(xTdQW-$ZhcTTtZA9|4FLUgFZ`mGl=1yq|4R1hP}WglkpW_g)2ZZdd2c$qhiwjAtU zzS0t`jz;Akwd+$tTeRyII)taiowwT)nQyH8vVYM?igp&X(g?)&y;sT7X(t5kMZ;nmHEBZ(ua8uQrCmCVh$be=6_amvHq zI0S07zieKvV(YqsOGtWEU4vhu{3k&p=W-kV1;MAm7u)B#ya9{-gIPiF62!hHkn zrL-ict64P@c>9Toz#WX5Oy%ZchTUn8-|t7Rlc2twAVBor`t7NN@Z$s1B-*mzR$eFx z72?CESDk@=AN{#-TW7%4x!U)Z5GFtQyyjiDPH_x}o7u8@M1ReTO|jG%(B?$NXUki` zC0w*WI}3saMo%a@PR_?Ka*9(!gJB_%St0l;2x2#e(QMyaq3884N+yd)D8mOPqBDiT_++CH_t8B*vslaN|C}+ph+(*z$4z8#&_McFut#ruZ$G zq@!~?l`WW$k?QrhNVGWL4so*Tsg&OKFS+bPhwDbK4DcB{lU(KX%DH{5*%vEbip5!y zfGET>K|vX`*$~vrEWCpP@{toxk}v5mJ2YKNqb+~iy=+ITW#?_l529s78Q%;PRfIU5!I%vM#io&j&0q95A+UQ_ zFF*(YO^%UZ2Q-ER+uK3c!3}mAcgxz7uJ&j67<=TuoS$nr1*EqZ5OF0tf~H?r99Yrf zzj=54W>><3Rd%q;U>|LNaSR>?kcXaw;b_v-Mb@gG9j|J;KN6dev=ZlE?kzy|ZZh=v zUbaUdX<9@Of{qI?;o9Y!zPq^os+Qa%NmCquf)K>8-J(|PHsj5e-hh|m@mxj1QA+F{ z(oukL4P-;cyk+PMT1V6rOMU}ky9Ym9c3QvAFwJsu+0MZ4qocy{w!O0rE&Bx*<-CF@ z7mPkwRbn!X^X2=s{D~+hbD$%&ANQ{=X(bq@kJ#V-xS)RKeSia47W*0r-p=06xK)Aa z;Fnm}<>+4`(J$d|w9pF~`amrK(v0BK7aE&BbggY|4N>9+6qsd(U6T1#lArdz_G}6U zCpJVnC&}w&p$?P)RnD(;lHEJ_DK(BRVni4Zp~Y*5CO|Cemi+DS!CT6F8!9~zAUDd}xPfby;i7Mn|=2RRp zq5Kg7Nw(eY39$NTn=)#MI=t=K01=Rvg!Cqs#>V5yN?x+`gT^hu7&LyiKw}#!_~8w4 z4Yt*$HPfFYz`(!&flO1VbU)UIC*f@drkKj)r!f}8h2DSyt^NOA;b}}y-U=3bXE3@MoeeM5yqtgE7W-&osBhX;R=Zi^J>9f6LP6G7r~ zLJPJDXXf_T9ePM$txPh}7Ks0DGbGq-#gC(lZ4*ovVjxP`O#Cu^jvp5PBu5Jc?PRUb zqTF-Lyst>7L>b*}`cM|JT;8TtWn`hh_W+kRP)viSx3@N1Dhy?K0miMv+CcBO(t|ti z<<|?QLVScMn02?E-*SY7-i_uc7QfjCU6O+v$%i?XDIi$-i;UfMDd2&h4#fJ=7ty5N zj9t8DWAd;5L8YA^^@|bhR~rju_0zIxG$)*`nWr#tut}{(fDq7gqywBOX;b?|A+Cx) z((Nl%BiwN$pAAB;oFKq8a)p+umwABx0BWC*^mxDE=mo9*R8`eK^E6_g-l^tUBMI#e z)tLIEt6op=c88ZavLCye0>)Iw-#;}HdtywM8vDNtgKEP{f4c?nrLc}U1A0253IQw$ zxY~`zzl@7|`vM(~eUc-0O2X)i{_>JuMwjM4$3eV?;%|$rfR`vzv^;9?C!3BbJ4vlQZ>P7n+n|2CiOnb^slG|Q~eGD1$+5~2b zG{*00+zt!1*To+@`6&^;9ilzIRIq^S^jRdLt_(5n&Nha#1wE$8uiXY?hLg4}xmT$l zoe&!C%1qeizW~4INjB+qn0T#_wBdkL7@C|UL`IpfZs}hY%u1Yn_In4hSoyJpPO`za_#%~>_E&}>a=_fVINvjC$-_m?3E58HIeCzem5yZi$ zk8_ZmEm%AaQDbHh)x$XllxrE=!9RY@;j}7qLfS=@r|W=28R@pXjP+MV7?kg~Hf0`CuVsN}o2Q4+N4Rf50cqk5G)@ z1tdxW@KgbKmeWW3CGZ@U%g1G>T6Ee(cuxHSk=7Hr-oMzzAQts602uCk`KTu7btuaO zXyRRL_QDH!-a~`_{-hLtF%w(a0SwlFFWH6X>$fVn&C*^GniJ+;H^;4oa``4DNt^%N8<8|rQNW5( zs@&{yP+FW6G2DR8=orw;0svV!#+YK(X$ z2&*h)_R?a7yB3mtbHmMy027ZBv7d65OB5QKHc@(i-;W6m#eyKaCaH8P)6C1-9hnjd zoO7^Ec&ztFRv1}lm;w_BKsaP^)auLp?2uWfis0S>z8a5C7Sj+T3kPm$_q7R!4scZnIuy zlwZ{i9LiD0s`}k%frdZt^cv5e0?jzejKipGI$H(D1fT}IQZjN3V&XeH!Zqlyi!y{@ z@)5vB3})8gDXFj7lbaAwMiz>xnR6=IZ_*l~Yod6px+~5b7QVM8+W6p_EPx=AKzDH4 z{!A+Xgak`8Ag$b;tvz#mz$}I+7*;@+C3idE%Z+|Q8_&^#b+UV<_!8Lhz$OihksaU3 zY4k*cl+CqwL`Xbl4qYW=MMsb+rx*YYI2IjfiPD=eTEtltr=s!vvi6~93@sNL#ipGJ zMslybKc@WA_x04Bm$@iGoITl-{=Cebzv~a|1HCcnO4G;m%KNZ}q#Te>)MoV3d9acx z?+O01Gq&|EeW@^%&+T-5ocgn9t-%~2_=*%@x?WATf_VpTTm?BUvnXRsEgghSD|5ot zZTNg}G(QNDwOP0>Nj(1CW_64YIF9Dscy?c=j1}`SjSvd|KKK3M70Mo&vt{5M)X7Qv zZAYxKL)M0ikkbGyu8ySBo*XoLM!qOOZJ2WE9Yf7VK-9CCiW~vEZY^5>fc4G47!45! z1#&XdSfcTpK?|7k+_&M9K1I(>YrR!&MP-Vgp$nd>X7a#Rttre@KuYTO6T~kO>Q#p;wKi7#IoIRMaZBmxyAb>RI=~Gb9?=(4cWnK2mu!mg6Bk^k1!w+aTguaJs9+h^?ikE z@8XvB$%Uc4|NY@G7mTd}-i+;*!Xno^q3uxuanR-h2v{6Ow+@0YH_k@9|FoO$<73ox zCQ$#`S#J%2rZWBAWqy-X-?qt;@@3d_S%ngWvqJSt^010ktFt;X9!R^zu?Mkvnie_1 zZ#mMrd#p5!joaH3V_4$}t=HGsC`Ddi`VNZ?aC<_)j{RTA)y+;h*3nO^Y7fyz(qJ5b zIT$lX7Au3$j`LfIU`f`w{n0-}iLyM@zHXBV{zK(}T5LWW7UCsJvGC2$u0t+T{sANy zQnn_VyMhh7V?hGlLjYVczIS_}K8bEXi!)cne;RFxB`V`SkVdaEd0nv0T++i(OsQQz z!ejCJa|DaRK&kpV@pM}m02dSV`M}4GViAAEL;jE<3W(lNFhgq!kQHCi6jMN$h@;NU zS+loW>P)_K<(s>kM&H;85@wC7;==ke?>^#h09Pt}Vxb#aZ} z6G&*|>`x&VgQD@tk6dqMMJ5raQF>lTURm0e;MNr> zcWQ+;#M!qMuTAHEqKy&vDp@YlZMU$6nE%hrUqh z^veA&9d>7$x>`-|F+E3R=POAx-(Y;kqpZncnhPYf8!W7vwsIvvOq;OOW=Y8lrW$ib zLxjJ6@GbJPXuP4^B`NPyzo$B$0JsT#32L-{s3;VcLK9EuE;5OFQJDLwju2N%tr=cd zlRFkA&@-OKB5_m%K&LF#o>eV0L|>Y(s#z1cO3%)6>PS;3G9w<3%Lr4_RhP}%S7-g( zqcodvi1rq#)G#|FCeVVn1Q5k+=P2ge*gnSUl@nw^!9>G`qUqa4rn`TMb;2Y|aqh2( zF!6_&$N`RjRHU?>j08H=d*;eCJYHuLEF!Qnsz3cKkYh={AB?^ft1SKV;9rKKsCrW` zyQV3>mRPooUq1QM#ZMrVLAP5+RSpb-ildXQTiOH7^zeSD&|MtTyVOVv-M4aI-yvZI zu=l$P;~RcM0DJq#X>q8kp7U$6Sf!$$dorVM7YbdJjga!|qeN0}#chA6w=TXxSMdU~ znJhij^ zg-P-uc;P$*u02$$KVJGH!h&R6WZln#zQdhIyy2pP`5wO{#E}Gq`mYVjoz4R)!GH+^ zZQxoY@>d#F;6=YExd||I3zUsGH9y44on-U4r!b0;9$0T=`_ul3eW zO*CLyUS9R&6|jkk!bkoBE-@cEG4y@@?UtY!D~3syE0j_6@85-F4(rw$I!@O|+fOfc zS5Xp!u8hTKgDbh?(C{H!>{9SPhbPS-;gw(>0bor#h15Q`houLYp%~kxJ6jpj{AGV} z_a}4bGf(%G#{)SeOu{M9l3Qb(3`x8uL>U1j4ws*@!EYsx^Pj6p+&C(^NnjF7ijv?J z*zDr=(LUFvrY|i-MkggN3YT56)Qox92Yp;&o4?>$Q4#o2_2pztb8jkP*lDGbIQc%; z=+hYtf2>?-Obt7l_&7f5IR0xWlMmIyT8@lPM#*Wlt(3;*G)y~19yq+m zA8i4uGXT$m;&ZYv8ACp}4O(U^jHVRSC>kKNbF{eDML^=8gUljRVpGx(Del z$t-1amnE+x14-cTlcc$lYRwS2@oU@+&FvAwo$?c->?yXnQm!6Xpcg- zcpWx}qK`m&mi5tqavVdS&PT(!i*`tzm&=XL;4^IW)rzzY7ttAR zm$zn(sQ1C8m4L6w+xqUPFwwr$1~D8YoS0F~(l!p!#Sh`aE!a5I>(w8Xy39q1XQxwd z-PJdAqP8TFrBZ+VY)nwdfMBWM`L@523Bv)srbm9X_h28$D{7(Ap(AE3n-paBm5Bg0>^X)hiO?GJ3*mF42Rk<&=c>(^p2Nls8r+R?o9RPo$2-nw>56mNXl(=C^tc!VvM`3AOG z37N6y@uZ;g>v#G(aSA;#!q=sp@wgHba~`Y5(a9(~2vWhJK6RD!kfI@P?@WY#Cdrkk zHxT6J>y8;Xpxh%v?{Fxh(V;>S?|9m+p@^c|qF6iuL281t&O7EU+uE0OMQD}BX_dON zu}q}?Zl|l1dz#ZTP-3^_YWiSab*qRb`i(#l!$m!sb<8KmN+5r;I)hoH ze@|<8iLc>4SQ!Li2Az>b_ypbC4XzR4<2f}JDhoDyM$5DhQnSUX5R+7avuV(oGTb|d z`g8!ezBcs{*efoo8HUTyFGk1SyI6_Y9kz5>?V-ywwhKrwU6tAki=Aad0dq|M!xkqX z^8mDtgv|=rdY^%?*PAe%R9>IXX5<%Uo-#7Wi!q&;>5|}`esReF2SeRMwG~ByTm)B3 zougloL`W1Jg&gZf-@~&$jg@q-4G{Ug6U^Kln(sdNERt(f3c|o+{TNg()+)*=S#x}0 zm9VbmEK#o>%62%O;&8(;dbNH!RTQrz7#?4UU!`dx)KDvJ6ZDV+@b8qfm^f((|650WF!o8Pff@)c?e@%k_kmjO(NaAfRZ%y72bYR_w@Ho zrlZQRPPy{V%fMYu(F}_|a`>pg$M&-5_q2Ya!G zRniv&;Dh17xF(z(y15H|wfy*$f`6#l36bTmUga)`J7_8dR8KXhx$X^+M8Cp1#-Z9Q9DK*zmn9YC!|5QQO9eohM*`*2Ft&`*^tc2DgQ z45*g09>U=s~ksjXJ5}KtYO(BGt#)2QJd;638yc%2To}QgknT8=&dIp(9 zN#mmw4aOftZWNO%d7J+C^jx8%ToxvN)R}Bx z4Qg)+wK!L=4vx9w)k0WuNaaCtc3o(QsD>;reD=>{;@3=jVgKi5yLZg3`ZiywQqQI8 zdaIL~i`_bFu_uwTF!#Jgy({yPc78J{g{7?8-olwr8d15Ctc$lmEjci4=h`GEZS+dvfj zEt3v^i#@4;COniNIQ;a#0nkAEW>mSLZC~*%3Z(OtivNcm|DM*K1a2o;s}~WkByDXg zYsy4W5A~8Bj3PExn@_ad9;v$1FU&MWi#Uf(&9E8GcK7TS>KZY*bESiR{IF9EMZ9yT zN&Er=TqALLToCB6%Ff=XifrFb8#{M}J0`*if4@(i`eY)Yw5=&&@>j+xo*$Rjzrk|L zx_8ps4BZLU63lZusM{c34zM(4;ok?t`tC2!eq-D!!a#NL=7e)! zwpu=nlN=RIFD?Wk;)sfT8vm5w#eB_~Wmc!{ugs*tgs|-+AQzAya`Su)Fk8J8pv2i0 zq><9GClf(3&brj-&gfcFC4Hqg_aA?b^Ex}m;yq^SMEf~X**C_;8Eh~0Dg6HR9_@58 zE{$5ttE$@_;l`RRiuM~HuOtZO)u5?L4lE`$P-K6wIK%p9NZy#?nLwUMi$Wn z%(2JWYVUld7H9{`B}Uv~Gh!EfX9$-9ahl(GX@96jaGvLN2h4(=2`*8(Dt7*`tHb|P zDhP?b?7OUsz()*;Sv-|q=+I58uay@t_dyINAt*O)WrK@% z^yV)yR?TlEF0i-JUfFC!1_B7gam&^Yum48cfjQprL1m^n9bSDAU=M&d1idEkHaV1_t& zyZ|>s!$!aLhYh{!P37MkC`IE~)x&P)P0k?mN|?0Q?dl<(1zc5O+v!TBOkPExNk;9b zquB-L@CjZWHqhdc)MNp+LvW?4%}T|ckHzIiST(SZhf>+yd!+=$^(}GcjRuU)MYzld ziSMiOvapOE{n%|uPA zw-;;c_>vq0!=L{%4dK$#NY}w!T}PhJ`41_gF8grw5f{_I@{Lyh{C|oo8m`3{I`6ca zU$2~YGC7_Y{XG}{N=!xMAU>)o=FcTRwj-W}`jri$oXI{+T}K!@q7sJF=xP}8TGQ@W zay%$206%!GSX=q0XV}wfoXz}~BSJmxa(+iE(=w%jjx)GBp&2?jEA;&rA%*i=UO_O% zS!S*J+w+SXBF!t}U-YRUA>ylzQ^N2ttf&QMn;BjU=Yf)n_KeF(OF10=scM^9mF#^^ ztBmhda2Qkd1iEtmX^I7s!ju#;YEA>Pu}exalp3(3_K0a2hJsWXc6zM!v_^WkXY_mP zS-Y3jv|g#CHKu*_K`mA`#;@1Xu@{rgsST@Jvpw16PHGlNy3t>*i4Kld$Whf#q)wCZMY4xjijZw>3;u6T zj&Z7nYun5iW^NSBDuF_lebu^U=AsgD1^(YxB(u$r>2G5QJ=K@|r`ijt*!1EL!=2t= znN(WXa}d(u>*OY-1I zCQ+#92U@wX7A36?Eii*36o(6fd*R@_wSWyI!&8xP6l7h2dXW=o;6id{dxxuF`ys{2 zCG*#s+9nz^G--Z)CSU0(W_gsHui7^DD|S8aCADf&e%MkK9pAYPtS-l|-MZ9yxi|%f zr@AjO6c~q+%~7Vq;u6s(AC~2RcK1|vQfI_x`YUEmPXiNvdNCf|6hn_H1E&^QO_Vk~ zz~c8=_Zt)Qa805@>z`(+zJ)f|WInc&^h}}p=?vh9)NgS`<~IXjA&_?*9v*(y%K+9) z1D?CVGH0k*jkuW9v$A4!*C;2odlxx9i`tSOOlaC>kV;@tT=1Bm>JHgQ1P>XL7x7}& z-V(>TTmbvnYu<7Ne|x@caF>FN@N=mDp@;9ycx4HPo${rtB5CX2dC4&52;&K-Hv+uX1L z8%*q@Rpq*YF^R?%E9-PxZ46#k)i_eGwr1K725rMM9Z&07>Oap7TqWV7wvIdi1${ovFOAG+B&rMuXfzh;%3Ake??R;vzGt`MTL9 zPb=72PTg&@x3EPKmYr@gPk!DK44>Q9MnL9-jM^0PSd3K^NB|2?JbnoY5klO|!1c_k z_nT(FnwJV?7?h7EG|Sz&NLouisy!u@`)cbfsl~`rM=rJapm1SGFWaa$wG>Y5(+rk}x+Pokku^E>7OkCsL|or%OA^3YpOY7W*wgHAhKj^(Sxe|t_~*t+uutOxfnvL1Y(sT72epJX zlA2wlc&zHPF{}{^F%ZoGbLmjq= zR!g*9iXSElXwtl~C3t5@7=MHvHl+SviBCk$ZZymJcbTjU|AG?o|k?>*dSr4#cn0_qwtl&QV;^8)BgEB@Xve+lRId70CU zI7Bo?j$vBUoz9P)uVLhKNE;BE>Jb*=XFneHF8@~&6@j7E;E%M8Vn2(hvimiN|=(7~>Gx1d^PhSPmGTOai^`2{Z0OmhsuNNu}< zh^EFZMdGf#30&uSX%Cye|1{U9<6}4uqAlADkgNec2OYtmMa(|!prJb+CJllmC*7EA z(#tg+Vw+(ur1g%%8|OKmYQk$giw+~|aUSkqmrpR}k{3jc#gII#O7hqY(wt*upNJX9 zH*xqYUNZ{6I2!9yJI->#?&s*_OxnJ=ANW1~iT`Xjx*F=nz$z46q<6vQ{H0C|J7gx^{>SWdhD^b}LT{V;gA)tBsh9VR6Fofa(N*5-{@aGgSyD4^H zj%arVE}~e*#zByjlka!@i|D2!G611Qc&ro*s;PtQR{n1!xH_-UdISBrdbyzA7dgY? zCBB3LxLkowtL&9bB9XG22a3OmuX^wJeZ%c$r!rQiBi~re@_NIMe;1n`uWx(I{ABVE zxO}`L_{SBChe!Oot$U-DpmhaRwXCL4QcAi@G6W7Nb%tW7*^&;I`*T+&eNDy2Vhx|k z@p9VRts&Qj?)kFCd-iG7bQ~%w9WJP2MIaird7%SI*O*%bfZCFVp6N>5V?Dk$O`41< zz(t)F#e95Ggw%4tJnqWHL1|Oa1Vm&}n}b^_jDgcIDdbphKYq?G0cyT>=XycPXX)55m2;ORRn3rQCzN~S@u4IIJ-@hBz*`ksLs zzr#aWe|tlGKbcd7QO;}9Zn<-*7TTP66^qtM-cwN@6cgI)3Pl9AB_RRMIFv<0t*K6$ z_Bk#k@#1c#Mib{?Q6(_m@ZsdInWbwj+Ila3Klcj>@7UW996t_*OfpudGI)A31JQB` zhuF|u6K>d5Ik#oqdd{0G@PS5M6^#5qIsX|I@Q!c%!sSAjf?xJoq-$T@?%(P1jpvyi z_SGKTt8V}OWl<8 z>{F^*(upZL3dpuVR)ktIp4ATwRe>e|r7X})?5cVM!!vT&n%_z2$G1={#tN*^n3_ciCG%ZNxLmo8dfn~_)! zvpQ&}T6c)$^5OjzUTQ;nN4;tO%&zNd{d!At&fd1SaSlGP*TaE;LL^C>*~Minkrc;y z69UXP&wf$H(z2Pryko)8~mj6qkb!{aQYefONSO9l!NAXV8n?R4BQ7Ur_^BnO;MYR_0*Cd zxv1d6u}$BpYc;=UvYO6A0@KuCaqZN16@E$VqLBZp?YHo|&5?I9WswUxMa_vWgmA$x z17(eGw0@VcZO;1FE09}P2SldnEpE@fDB;e-J{$Z<>YCg)%{z`_E`1DH76^bZQk<_{ z(s-WG^8EK(WI`_dW!mxSo6vM-XKd=bgy40b;_BU5I&XrrYAYcvHl&CN0;XiKygFRf zv&0!TG68#E86#f(tTupFjWgm6&mzt^>URd^@cA+2|DGfm#0H)q_K)ytiPbKVV^liMtReM0{HaPb8#eO>Bb$Fk;1DRjvE z>9Gsw?J&6B*G-8i8;%c`=u%=P?Gh5n#aOYq7qrKiP1{OJ>SUx&6cTy3s<0F#`@BVT z|EqS}*L2o9qxQSU+_NF?M~4xkg-&D2Pmi&=9%t7g&#skUvzqgdd;0N#C_r489LNO9 zr=p{weP!x9TDngk-HYt`X{VcznlMi~9_iXWKjN4{q@WK(7U;pyeyApI2XYWe{68jUj0jW;uq+QMx&-?gY&wU-gl*E7@R&0ulvtdT#wup|-( zSa3T0y~#mFMj-#i;`7)s^mBhjXfA(%O_DBr_j^AzQIIugFaiUf@s>xH&@3YrOlT?C zitb2pcR#7|0d^dcmnrX~CQ8ixz(9zUsX>fGrn z&iG$`QRKkyDCJzGzo;o5P@kr*Tofp~w^z6O;a_2qK++AhJ0(7x&xmCs-Z1s_@c770v&n z;83)2^`y|w*;utL!`frj&D|J6E2$%zqUxXKaF172qJ|2v_|Q5E;_2%b)ECFZb_PR_&@XK*3Za3gx%@qzF^_A=Bw+X!G2MxS4~dfL zN7WF2$BPgV5u<(YE$J!cf(mHK2umbiCr%ds7Ys-@MNQAPDoS6EBUbwdD|!9ah$lEqi+w%N8+)8jxPqjMln0FlCc@J5y$rKJBS{o zR=a*w#(yg*D5^=2Q8lBc(tm*L@W8zEMOiP!cC+o966xy1rokEui?TH~O0>FgYV|;E zFQpAJuR~l*`~Iu?->fHmhjs^)GnC^httkxXpaA9Jp=R!?CBL6c09?R+}CtS;=b=avtmIj&BT&q)F+H>I8%R&iV9oIa8J*mmQ5`{GG76=HcS))l`+G=1jAita9xr zJqK=GBzI=CD69v3!PySIq+P~+mvG)a{h2%^_YbxXWu_wc#>@*`^&gJWz3Q(o8&w`Y z&c#I2QhHu$(W(+2%IU9IxQtv@S*kYwt>&>x-2>vOU_c$n?uF+6^rZ^phD|Yp(WWJ# zu_U61%(Pj@@=r_-t~jaIFFWA&%tSfsye%%M!z`8lzx+jy6cch$KH3G#>!d|ydNWba ze_yp{Yp@=xpE~tR#;$OhKAec3Z!NQr{HaQblfUeg`e!gz0N6F%&%DHUEz>`bSYBWU z880OWZc&PkYo9+a;;8b_Bz`#HWAFGL9bjAxDgJxI#B-(b^N)K)u;15ZFWEjBEB;qI zv3u{2^2S%4m6=q?+!x_(%Xarir7u zS-5`F5&e!y$Zr)DDuYX#&!^8vpZCrFnZ0GkBYd6^x!mVutq%%5&bz#-=5U*LfxEb`lNX=E^~jfAg-O2?;@pt_y*TlocUW;ACV>>Yjw0sd z6SJqap-Rp5`YN)Q$`>+~(Q4_!X-%7~-4^2cPTT3l>Jf}ic&CI7W!vVLrCfi*n`{GI zvg~PVc~Fbrrmv7OI!KUeHvDvA+eM5Ms!A>Y}X#D&FfHLfUCf7LE+dakT zt*>ewMAX(&6x5_He19Xu&@9l0Y+{ zjj3Hrh??1NYt{4|?kS^!Qku1~)#sH*d!_EU6CaH_jj;!@^uv$A_lv_HPJBEit_*}G zM~HA0D%p9-7;yG<@9a;>$`231{4C!(;s2ad^c*h5)STL0S=|=beNQa9GNhWhCL!0P zKZl(Z@ogCUI<6(4@=8(St3M>buU1s{SvU|^mg-!S%V5as*O-pLr9u;F;T4e7dh*05 zb1=_}`fF!USIQL&Am;!O%MF2ZUe+#i-Km&+XZSw}s-P7An3#u|I{7>r(a%xMj^Bed z=OB;7#Lb4~)rht8CrE?t!8-MHY}pG8cSC9o?tFGa%T*)B|QcNiKvCN)}hLmc&m*zBT)DSA5m3PI*{w??6{3Q2OZ6mt~tx_B!pw&853;bn;i^UU?Kq7&CdK7!_<|Fqq)#=b~dEUk zzK^%lDJfFztBRT!wxjdfB5v$JH%+GvW*eWN!s2=sj~7m(Hzvv44^%Y)8dOK`SbsBq zML~lEL^kwO%iKzlkl1Wqwo+NXB$cTav1%y4au5C1tO&#|oX9#fbn#JMZ}4gD(s6$L zfXwJ%bvY?w^l_;nszZOg?Oc9-c?~i;@h*koz8N_~SWi*;Rcu6NdgcWU%U&~E#dLMz z*hi)rjNtUIZ@rbOK%quQhf#O=Gxw#}Kkd;9|CZpyj&`VG z8=($#{Ba83O6ja{)1xVnd1>!%*I0VApc_Ow9g0Z3%$3iCWcLgwDUs={Ld2LcD#i9{ zHa%?-`P)8n09cA8v%M+oBnX28=+1hAcB#r$U>Da|5q<*bzh}5dqTx z_(U5*%@_$N|+0%EBz1(QB=Z%Cf~rPDA~2(H3IK@X?Rin#spq9)cdPp$Cy)eEE01y4wtaaH8&pN!QD0?!map*p6I*7q_%)}{gv-NT;R9Vhhn4g6(%9pUT}UOj zp!j```o5Bg>oMK#xO}AXB{8?7`Vi^jTTjGe`!LNA$vO%y2g&kfYfAVA3-U>ZU|rPk zX*9S4wzlFFC#f*x+H~|Kf$oS-Q^o>&3?tDZF5Zvv{HGyQ56_6uUMPG0oma;D_-5y-dM=ji z&HVu}XIo~`gF!C4>QuMa?w|PX0)@fzQiD8hk?1wN$QzuH6fy1l>vf=zv%hTI{DDXo zKXn9I{Bhe7uFH%|eXXxnJ{_vQx;*2o(|x`YeWE91c=O3(M>^ZV{VHUENoM4KqXW&Xt!= zgxX0%%r#*wZw0x3zg)n{Cjvt^1;5eEiO5zIY&h!oTgGS=OZZ~aMV!o#oEc>VWAG+= zXezuC?t0<*-_Y)HbAC6dKHEVHOCpZE2x6}J(2Az`dt3ua2><%uEvVSQModk+7m51} zOgKp}vm_udKm-ILn(%O-`-n~Td^-U&x13OV-~e@6oBLRq`u$Uh#Uvjx9O%DY z>z}dL<<1-jSRt_%%NzeZjQ~S2q(?}-5=0>Hock8X|Cz7hquIWcYFuicWv7eW7(h`~ z9r!8OyE}jaT#0~OBA(oHP;a8zIs;gq14Jw6`Xg?a)q9Qlh&wtw4VD4fuxAP{_m(7^ zLgJO8KBZ53{I0>$T?&oC`4tpGO&vzg%Q+nRW;GcXzJ8!WgwfP=*T&E42c?2AGH-9U zcMv`Pbq`mcUq=_P^wH-?qn5$DQWJknUuzeUN-eS@$O2|gI_im1{`t(3S>tcNmY$Zb zj|5R;eOD#~QdwZWqfF%i819(+`Sp;F6wT_p8@qkg;lYrpD47zwcy#8qOO|)MkkYh) z%a=9Q5j_mFm^k{}^yw!v@$b=dQ2{jdjA9_Y2RsU8fPDiPj{-GbFyIz&o|J3m=}8LY z!h!V*%y#o>*YOD@mOC+F6|qy{{>Mb!!U+`kY%SE

      4hG*>{)(@C&z zcei-@DjP0fpg3#~CX)FEBtG5UQ_zj>5LAfU#VotifYbezahuaE!8u=dF7!5cOZTKb z0ys~@J|4KLf%5SD!h*t^UJaL{MVn+DaUY%1KVf`Yif`fIRKjrIPRDMlmbs?b2{St@ z7?hVd&n#lvzSYttdD*IJWo=mO#8jxck|@uOq$yTW6kk;;>wcSgAXDh{XoL0XKDE7B zQyn9vs$4k!Gs3&_bDOp=QccOew$+kOXn^Vk85BFZ< z80V-hpJ2 zRWDAA2xU@NEq|OM^7d(-XMZKJ^QVpEy1KgsZG1~q-GjMeK@prt_UDC>jO*4Nna{>-4$a(^Cfc z=ak51ET>zJ%0D=Ul=EfuSBaY%=w;_qF0dzg=*$uEJRWm&>tTNw2&yxQJp?N9%Qv;T z58I3o7;*xi*Xnr!Q-l%+?=Im5@TF^oxg60TwVSAgCRl+Wc&1uXKu2PV!*k1l^jbYj zt;%OT!?319Lup^Dvs&?^#hPbIicF#=_4tUVrge1EfJD0kH!jPRl);SwAzy!AM!nO9 z&POc)6Rj^e;g&>OZ$!xy%hdUJdFj|JW0Ma#i+6oqv@GgVY7Ad?yh2cy@5!R2Mq(N+ zOn!kBifH|4XK1Ntgqc6Q;4SqS z2_&xYdN)3iHn_Z;V;zT0Zh&z;wiq)OVMM}k8ZdNbU^$S!<0^#)tWmgAN36|V)4Y=H zDUsmAd-D$pj&DnBqp5G8Kd$$Fx6tYOQ{Tn>dI;xTzFlo;e5=ipq9|P^gASh>21l`s zW-viwRvh;6-QPJ(ypg8;2JaXL!@6!nOipReCBA?5otIq>T=RkWJp>MT1xT8-d4-dr z)1u%%xsG{u(C}_O;*%wcyu6D4@NPyQJ@IB!*{_p0<*j;FaPSn&ROHTa`;V;&FNcb0-L~yP;2Ypui7#@HeJ?6 z9LU3sbK75Q&R(EewtByMy=mBaX}ESV+t_h=@kZtGs#rss3eULJ<0y0ZN8j1jpau~# z5XJBAh9|+ad?5yeet-o~+@(+4=sW2k=@jdQYR;Eg5B@A8lg5Jxrls%=f!*-hrP;qH zK5qzH8QbIjl77KdQ&(MHzUb~DRDO845)Y>o;&;CjRv*iC z+wG<&9WBY>{UzVdT`v2a?0Uxo`Sj6uAv-Sn;ySFCOP>-q`Yaedg@fM7P}F+&+%JdP zUl>+N4$B>GmMYca1ZgAKXQ;x*zKY|eJHvBe|0;sf$U$hw6V)Q5tBNs+SR_Z4GGF+XyDT$qmx(r; zLO4hCkJ;(BALZIVgCC-y-c3(oFGjNH=_#dEsWH}S@gjRg<$jM9T?eINUlbwrx_Ac) z=Wf_TZ$(Z`JJ0A=uk0bH&`w8Rv>7{iE5h%TW}=Q@iOj~66}V{{?;H}B>6o)Vj$5rf%%aItmQJTBI3EZF4sgGpxK=$$?2 zpR?z+a%d9KdeT9`>ANs;+S+;F>a}*i8nN)fgO01jQm)hgKDXU*E%682?;FMsJ_0%tIM52EaL3j}6*HAjHA7nY-;jn(^dZ6Z<19 zXK*IqLrvh@Ty^yrehu0VXqr?TDV{3KSRZ~0)MV+cr^4`Q@UM2L$W}U$OwaW_Y36yD zpP66eZk1ZS61f)?)H7@F|CK)GtF8?~40d_Tz=mB^?+!ujKBcUNnXe71p`jtuh~CZ4 zd!8@A*5U&{1*Jp)W$t}*Zj8ur6QXy{)^wQ`j`D@5CrRWFHs^zB=C)(^8X&{!dU)yI zomE>YAFOqAU%ECT4-x0H`-517hX-$}^rKH@dpW}jElhqc+2#zVskYGftl0dCAY<;livMpz7sT8BbX=@pS)(XUO~H96m6i| zsQp|?on@Od(u<$w$+ITgEZ$Y~@W>f9R;)gQQEo(&=~%Fu{6Va)L%BX;2hJmkRaze* zCPaGn-?+cMWGmIf{CCTnK1T7N&U;U2H6~m=INViLRRaQj5Q(+3c+d5@fTOvrp_St| zf*4^^0q>a;Lz@#FAh3hp_r-jFaBdLsRn}W(_0U^E*M`DZQ!O7moF z-*;}eEV*nH((AJeR;5gRZ5@y%kEnJ|>EhWAJ0!e}`7}Uljh=Xe)}1j+7+*$=L2ph? z8N$&`_X|R|uCdFNHhO8Jp-cSZt0ebYm^+#>Ix3jLfg$u>TqrY#af=lKpKTnluz{YN zK4FUA4ykSON?hu{yhIjk36v6_Q^6GWRKbmd|ZDtIHTm&A**13O9Tc0Bw1;<2^2v-n55*I zJW`^~!_9i{#+H|jSC!T}DlIm*e@A&KoGO{Uinv{`%h8VM)XIRRAg%IcMEZ3YBHqxy zoCDJKwFt=2at48V)4kCW$v5fInOV#FR`FnB8!@yn2Bj=UKRpxX9dyEFL8p&lR`-LK z`ajqdu5GhXQBmjD)&_yEEx;s3Pt&fI!vsM0bugZ4FbtCu;cbusYuh$GXE*6n3gd)%I-{*(ZIp38FCddjL0$Is;aYuyqwT zMjZoqO)krIHdNH$1nypv4Y(BS|HwF&eR&#P`e&WDIt9X_-H5 zv;7&jIk@)VQV*$6^Ri|~^(h5k7uZkYP8D`|1bP3|D%~krJQzm(`QnL0o&DQV8%@~b z=bIDSz|a#^ILA5Zc^t+M3X28x7*0~p>Sf$)KO5Ks&%gCoHQv}J_lt9z2~U3#PQi=# zxirWAS(6FFb^A~ECLB<32Vlj<$<+}zjYB+wHLb?1-hgJ@l`~%2ucs(*;+&$KmOwC zzhZ$6c1Lf_fNi+|Byh_+^_u3A^K9$m7~8XvL@;Zh zh2V@d1w6J~@HsZ^`yB@^w7hE@XPvHpQ#E=%1Ms3xt!l@;2b(}9Hc3oa+B?KPJywJX z44z~)3Njoxor8c3Y%>LHOCf{z5+6Dre*g!hH_ZL~t@t zopd@nAu6id`9w9O`RRal&@+7i-kvH*rraCN@Tr?S{&{=09$<}(?YTajb3%DmACEn^z*P&oPCDp}-_E_#86o!Y^e|7L4MS1Q z6^%;p|7Y2BlZB2V9h6E-k$7}^I&s9?$Z!LyC!Ffasn&W`I>(W^z8${$sT_E5M}~qP z{@v;K9#R#GX?eVpN3X%srwfk8ettyLGS{^gHz?t2b}`WYsYLor(ZC>DkD4GlEI1rV zl_1dN5fh#d$&7<)P*<;$k3mzv>{#6pyYV9IwlJW05eFHaqs3UauQmA_VT0T)X1$YL zkRZl9j4nCrBfR-3Cmx)g{Twxt2AA^V$B+5TltMtioY*%J{+(|WF5 zel=;+|akBmlrt(O*7?@Kj+E&SZQHHYd zaR@IgZAl5`QzPXkr_ek+4`#G!NUbC=UjG?ag!GSyT3WnE_)mb9eE>GQfIpw!UD{Rx z;k)-Q#(w2&-ZS|*yS>dTJ0u5@8K_NFF1?s7!MR}L!@0V4zC0k#67wgo@#`NsD@Qen zw-gbXU(IN3`fL0)m0qWUxZ|#(lRWqKOKud1-j0C17=Xd!tsvAFT~ALPzQ@2ygcEW* za;CEOPesuCoUY@bq60(Xu0SH%5qjk~NU?f~l5D+?V*!kBKSMr@wa{fR=l~%47U4}c!m-|Gj_y6a0W;HyT)LH z7=0)rdRMDom(7CwjWW#A@=*TElcTolk0UqRQ^m802E9)uqG35_8+|L*?{F1--efgr z2aBT~EZ;TrkuV?1N9)2hd0#Nh9=ij4zX zA;ugpgcH9#5oa&2NY9RoY_D}%$tCKsJ_|Mei$Z?&~B&>;Hw zZ%RWwvz%wJEZ{e(KR$mZ_UvK3h|(j-q1~63!2&w{o#$p0JUTwMs5jU+Zao>Ox1R$H z7;soRo3~7mO^pUQk7xU#v8v$e(vs_UL?F%r10mYP;4O$>eNWifh@cvnolPawtnw5g zu5^^m!>QsZYolFx0tlo_ep2VJKZSZYLQ3|x(%p$hY&e)gv&p@FZWQP{Ukmg-X(#pd zy}yZDyTN`qsCi-m-{@O=JG+DLMjf|d<112!j~~A$p=TE|aXR`;WuCq=eVmzJS{roZ z37Q@F^5;Bd_H7zx_`pA|d%)t5a9k=6YjppgFcHxmhFzANkFLn%{BP%- z**)aRXzwB23Sywjx_UR;xS1dEqK684Mzz)2aoGCJpsH=1jYJQ$oc;I7xljK}U<^`Wes zJTU%i#U)wEC&7Hyw$#8_M3pF1MaoaEOYI+4C;i6gjQ-Y{v}zT?#pD3>ayznbrJPrshA4j>NxuXIFoY zqmm!*X#j!%FC)^DudD{ZQ6P~5zpeCfid?pZ;Ec`1N56*;w53Z~cj;*4y&QQn%|ow| zhC;Qg^7vx^>c92N+O?>uD7P5>dX-V2K2mpS`!U!C2F2Dc#MVM^15WWD)Sy!mun+<} zVw|_11*Ghoq*>wC`=SWp0^8fgh-87NBh2p-z_iN)?H;XgpkKRT-?3Y9wqts=b92&h za-UJas6?7>DV_@}M>Tov6W{=CoOirgV!k8*4Nh&}0+1jxPPSz>}e)?fnFAfTkb1I}v34!MX3 z98H@4ymVTyPO9OVMDRb>g90$9;`NV)j<7`e#HFxG{ z)+;tjOgoM5*K>!jRC7e5V2As^^8k?2$?35t6#d5?G^F#Y_~K?Y*Ng0(=`CW@gEWLf zqVW;wY0f6?#y8gw!P9Y6c<}4V&3u3}IrI;a04&g&xe+moXh#%H54M2E>bxN}jS%59 z>iVw$0u!rKGQHER)L{hyq~o~(BChDEV%u4qW1q2SI~vvFAGx#D>keG#Db*7q*r@QG zH!)Cn=pOVo6JQ?Gb9%=<)5i)3G1b$l94sA%Ma&yk(|@u}7qXt4zMa=6>x{r<_H>i9 z^V!zJmY_2w_&moTO$=E4h)RGwY{5Jh;36g8F(YNG2Vw-R6g%IxNM=+-G?>4V8KMfT z$gD+jV(=_$o5rp7FRSLrkF*~&2#lBFXFF_NdvpMt0zf)h!tNL#JhCZmdmkUcmk`BY zR(;aM06A+SaxVtVp9w}_!lH0vBdRw0_fF493IWpj_U44gUNNI_Rdwo?4nzPesh~H5 zXKPQ5P)^uZhXuP+_On{7skH~>*MVG;H8z7y)O41p@06`9`Ad)+Us#kVni6Vw9- zEXnK9^daVE!10bj^m^G<(D?!BX^`p${^1(h3k~di2!oJ;nuuv2^dT2oI~5LcAcy6q z-|1@!`PKG+kB>KDNTa;G2lg&rj$bfzMf5cKjWn8r;70YZj(P^TT4K}N6w|22wjFk_ zn+=KnFHmaHbGviSduQNU|E&nVPbLl-Wj5 zK{`qKJWIV7{iR0~-G{x~bf4C9^&DpP;ybVN?V-{Hz|aY23)eU+>8HZzE|5m+bsvz2 zA%Juy-j7Gx_*$Z4`gj73mPWNiYq`yvaIVHw&Unu2BD0fHU5E(dVT#J1662(Qn-qdF zLpLaG7p;KO=H(l&s8{@lT;TY25n9UijH5Bu?S2aF4goWa z#H~W*9EIP0=4vS9YW#_;4&|VwXT;=+=T|W=(0VXxc0qroAA+ICF&T+MIGiXF7XgOdl+k{jXR4%eFi_?^o2} z?5bda({CuP4Sx;#2z6|Gx~v&=d>C+)v_E3l`>)aoBRK|N_!8+>8+C_alAZ?P`oRG_ z7(n~9x^{n(&lBc&-{6P}_izt^y53~e+}b_FK+Y`j^GXIdrWJednfJO*$rOS^=<@VO zms3w%>^4&g3Y~iD68>duasD-J%9In{Bi9vg|nQid2#O1u~` z7D){9anlx#A1tK;g7sIxFe+sSh3a-4Rh6_`1D}wr-;aaPDh8q zIKWYR0ytpt%QCgCBS#2D$Ck(wKd2zoK<{d{a#~Ni*B(zgNC9%@3IO*2I_&%c6f>43 z76S-zr8JIBP@;JTwpY+~$F;u~NDQ5xdXSgB_p+OyPxslq6IML^3%oW?bH<(+Jj_J>z{WWqXTVvE#$5eU zxYhIHWX+obi91@+r#?cj-`Sp<;5GzO;JP&?uZ`#C*G$c9Y$!Orhx{iNk)AiZ?GyZn z72y^sE_h$-fABdcCYdzy`RreJmO|SmS!IONZ~lv><+hqfqDCUcovq4qStJW7X;0Yf zgyvM&*VkwLAmP8ctAYAF0N;DI)yry6A@#;1&BdjqUeh}z2>RN;xV1=D-5QGw8$DIe zQ)!7C9l!0zlm241vt~f39uw7pl=l9llL}USj}ZSyBl>i+HUEL%VRYqc#HSvR^n$4E zpb~TGb40m|gNr+g6E{Rs{!1^bA=7ct0IPDsHbL*`Yqe(-25)|z@Z^yij9B<%MWMRA zv1nV`O}P`&2mvO4VWu~?(8!CulfF6smAUnbjssRO;{$N2+PZGQ&PN!g1mXO+?Lzh8 zj0(#AU;1Zywp-IR!`T$Az}?OHILWzD5^w+k1mpznh7IHj+V!rs8#IP{cr=`WAbEdt zxOR$tQuwWpSCY6x_OuRi-=(!D55LDPUt!3*3H=#*yDm8A4p;A0_xySKwKWcBCwADxPrxNSn9g8 zdd2T|Wdk93x`sYNLV|mGsl1*+&m^8+s%DGt$I;WPZv8FL_L%v-=PjRMQ~D*s-38Ut zX?;=m9w!V{wKX+0T&g?qkksZ*Y}hNTu-@Zvd+qAuTKM>V+juYFbsQgO9g!pIZmim8 zanqEn^uybG=~b=B7!IZXQgJx5aXLLcc>fm;KtV}MO)Lz&$<9;KCxriqq$)>$)*Qcc z14B&kdZV_+HqHK`@sz`{{!yQeV`ci0`dU!wH>nB3@w;z+kFKJ ze+lAurG!SU@;-9Se);ZYCoU86kPZN2B+Hbh_IYZQ4sB@wP?EBbgQfq2Cm@er-{FJ^ zfvU}E&UG8=xabAe3%}FX56k0^lwjjHA1@0%{2G5S6usTnYJycVsy!czxwVduHc&yj zd^W)8O$&oi`OC@kVDp0S6mSZ8$~^-+C#=bD2jgi-;&$++rRLrT#s`8;qYFAQPAeQC zB01i>wje=3FtCTcmlNN$`)`7RUFMbzY|#jZm*ik?bS8kMnJQ7E9dQ9vXJ4znX234ov-ut3-Yw4N|5vtOt*)>`|(FBtI9 zbRh^kSFpNWY7QZzDy(A!b|-@kBl`$MWk>KT?&IIW9!f_u|F*{&nOuh4`MtQI9pmz zl{0((0kOZ%e*GgGl5a+)!|v+PM`ZqYPyRK+S@B9*BUTPX_i|nc?TfvVSAE?AM^@ za~)UpxsfPdg-hXYu>B>8RFnB$Qd0YVpFHQw5gE>~>=@MP?hGM*9ew&W3gXUO^pA zfP*A&A6i41A>azW*>pO0@pS2Sh zT-(mcjv8uP*SY*G^s%8$e#87@%QP;tR2vGeU6ARUV0mJGs7t8hyvkND$M)m1 zeMw}Hhm+P>dMiq#`QfR&{1jkU3;^)^BO7n`E`+L$Ti;d6UNmEBW2Jk}2jDh5a>U>r zsp%T%4Qlwizqz|80PtRBqowI_LNLjGxb7V@pLKYWXoR>;GdrX9J6&FX`PICKH_LfO z883tk+^ROj>}PXE-)-`|)*u@Aesub+R*mveAHHqpR_9Q;UiKCAn*#-H0DmSZb#?93 zKZK^z9k(CfnaH(>!B9$~)o>BH{=wGP@Raa-gItA(5!xW*T%RTdx}r;WcnFnbk++t6 z@!euklv1$Dux9rqHxZMjl)@isxti7iE_yvT+gb8E1DwA9X&ppK6S0MRr{Nl=c&-<8nL+L~g&4dObM~uYwCB(-AR`v&!d;`4$KLu%K_c3YXqnp|I z-?+Uy+DrCV{FAM};tWYAJlhdzPLjtbewagR19SG8D|$^5%)~|iTRK~gjR~?1Gh!5>V4$yCXyapfe$5ezklt6zM8v(Hl_!PRrk7Vdizx!wwP(`J1t9Ab6*igBx)Sa|DZ`^(Lx@bLhls6f+{8f`FY zH-DUGx$|RC<%!;cClgW5pAHuVEi9-aN%pBR+FHoBPEGH-ISh919N)#}QBM62Ed#;l zeLEYg3)MCYjXB>c>Ew$-OHSLFqI(cM9RkSquZm&O)>{8Xqp#wAi?^NB0Y(woZX(~q z1Om0ndm|AVG`&s9sQc`U53O~!3Qc*S=#R;$iq6y%ps>?>wlyGOy|Rv!BX0Sc`PkBv zZ0xPtTHHi)d`v|SLVmKf3R=Alv=Dn{bUNGQlOczhOvP@9SC4^zb$-#U1y+8 zsL^vu5ZRX6_0Zx9afd-48*h-Yh$tuE&K6i;j?*bfTOz!hl<>V`103A~*{^V=q(B`6 z4%^@ZOdsP6Wzz#%YI(n~>-z>;bP5ARgOORHYSm#zVwt<-d<11h!NdXK8Bbf~<~pL9 z{HwLAshXG(#>;}k0Qrrw2;;|fHe4E0bNxfcu6kl|UaGbg4E47)*lm`Ui%avzkaI>z zux`hB$_yavCQCj)r`jLS{(mf8Wmpt#+g`d9kdh8jy1N^syGxX2De07u?(XjHrBOoZ zrMtVk+i!T@?>P9wzuBGHxv%TY-X0x931D&_ege3*`_MWD<}ZLq&JpyKm<+J_ZV&s# z=kdb#YOk~bFnS@8_e7@8*7D3@Tji0juGF&*|2`-Bw^J<)ka#|IO-hZh~F&mZ`gOLeZl2V;*ALYrR>KS8Dn#lurjXNflEu zF;R^y&6Eap28=IRbInz7QP(r@1Gw%^GyvorjQ5cWB9u6qk7f)2?>(m^(}$-(G=Qbf zVDwjxdkNTI|5)uDSE({4QhCf(G@MvTBoZnrEe>W6RfSS=keERw7Sb}{&PLLnAem>n zC3W#R1k$c;w8^3rD?jkk9FPB4`=l2XG0Tb~^~E~OgzhrC-GbaEQ$QZa^#!L2=@0}| zKIOQUxyHWhFzj%S;mdV&6BI^tih044sREKjn-%ffr8FOl>|>thUvSFszJfnK4Mp6G z9)wlm-`J|)*!mtnrgN??2;MIJWH%o%nkS|pMp57DkV9eMs-!^$s>+PaJ==J-dx>S9 zt|pZLGvQ;~zrNS`^4~oGsQ&>P0iZLS06m=_Bt+f{pb`nHZvP%vzX$`+x)netZTt;? zWgHtDcjl~RUoo)ozun<@Gm5c{rfOeCbI(Q$cAxJN46l5@cTrjs(1?JZ~C}PO8 zey89oLN3x^VCAdX#)Y|qhQVjDj zB*y?czO%?9nf&tWOf0y^&)t#IjkCSZVCteEb-WHQa!n960=Kh+pA(SU z{6!<=ZM9FU4|Fws;M#cvNS=e%ULf@CEC~Qi%Sk=ZQJTeuYhan1%z<0Bcs?AGjYO$Y49ne$7C^J_EHt@4q;tlk4m-~fqWzuq0#o8W^- zt(4gf>?I&jv0^qNTj2XuPcqfYr&;fvYf9 zgBe4Yi!fWPQp(>B-U2^{1*sfAZ1gt#wa*iUr5gg+PGGra5hL|&Pch=kY-=xCh=`B@ zw~VLR%7Oc!+W2oyhyGF=l)zUHwJqWrNR!DT`+KHXi$!_ ze|xtk+Dx+C*Z~Uqc`F&O6?q{WZa+rm8ZPwarR~GA?1 zHM9XfGSf;A`3_kjwY89Du}5ciwi33q03W&JS>=J(0}Bdi^k}QFbdkX@;Kd*$iMdK!L*{o&2&!BS-E}p zNf=bt{KRz#q0dhIH0U6%7aBrDU|NYVqWiTw$&1LK}yVEf4rb^M9RN|uxDWtvEBfl6s59w3|73) z*qOGfS~1yQu%yesQ5{0XRJc4|psTEh_Q4qNQ<(LdR05);$noJ~_TsnTN+6yxSDkE0q_Ro&kR0BMHB1CWiLH0JrZr{A@YyL0y2A8!hT)*HOkSA!a|DvA6yA z>4CXf2!if}DxBG06aQ8nsnAODU&|ECU`jEa??pWN|2ao`WIo)h;HwC7TJj}N(=22yCeeYk zZm$^9>(TKC7>8d4ae!f>Rq(eW*sPQa9JbXs;j39g-`3~~;YwOsunbaoZ1ig#ID&Eu z9qh9V;KDXA;+uzUqm!&4XqI!{+};uf3*|eL2)n}qq8j2VgO0HInfCo`*2N|>HPkg| zHe!FK(WFH!tCqs)K{HvFum2nOSPC`N@}5t1OIw*EML-u&352)*;}9FrVp(OS?raJw za%Vm$6El>LQ9`XR(u0G}Q;#`EmX&>9l{@J7D1&BGxX;2p825uWg^UK!!Ca zt$>?!r+>^X-Ek1(tp{8UI}a^&CvQb)LcV?E1a9f(qo$gA3qf{kS!ADO+47 zmHNew(Of1s+|;P7g*#XlAaG%8*_vS4(X#(zGUl&$r5ok)E5M58%VYljA=hEi z6Hx1GeoEKWcvV~M)TgqSTiJA;0%(dhqZR;{3sA*}vc7*<;*A_J^5$=`Y(=loQ<$_G zi=wo%Y3J-{;~%*?D89!7EjJRJ&1#zbc+hFkQX#>qy*5j=nhpLcKNl^0gO6Ty%uN`_ zS~^?iVygcZz5n?ob$}3>=8(?aV0#C^kUV3HnjqGw?>F~pe{^SoR#qOz8-}7uf-InY z+C(R+On>t#l^tkEZ2obH2nY{Db!QQe($6cLBkNt4LNhB#5~hoaslazbY^F)fX#uTO z;+B<+RG{h(HE?8wckaUZ)Bqv{jIW|q8@Z9^~N9(>RATftdR~9(zoNj<%mb= zr^c?(qStTpC|qBR3YE!*?gHiJJael*{l9Cfv+#2dO4T5K6J1ulOJCU>RPJkz4SJR0 z#+0}y2&>9v;F0?OkS*Ko{-H<}kLR`|R%$zZ)HyQ3RWyk*$ks42%`#~Xl^-mK+{1&R z`W50zsY#~`8X3a}efY3FkkpC^xxYE&>A26uiTImGqpYR=INsYjo}!Yu`x~~Q2vlg4 z{7L^=mtS6)!i;nO*z}kI!9_nkDF-42=u?aiIDT|m%(u0*HQVoo+h6v+oq~)n(3{Ro zH8nPUH$J7ZYGatRsF=yC+pzJW4FXh_nT?Br ziTg>NdSp+b;E>;<$ILdoxsTpgL3u4%_aOldjlW!vv9@xr+AW;4L0Y5YjE#b5{tQsV zjIF|o)noWy3a<3B<<=?rx!$QSxfOIKrcq^KO^p`D*^wuz7pxp0PZtDcgqghV$xCgy0GP8vJ5hyy`Rt^T13EPPA130=(x~=S%^eGq0 ziX^W11?zsboM8I4no4yvmJ@H5e;OJxS-+(;Qg`*_QHhU^*OmTlMK2qg%veoMnM2Qg zS&4|SUy9~Y#)W=LC*#4F_dioeCyQkHpf5dY`rRh7aF;3P--JI1)ObClb!2NoZW(Qc zM}EezCFV}yqTeVae0DuknDk#pwXCpXwVzxqJqBld=4ZrsJAv-tX+I?0#Qh&`(Z#E; zws{d;#5DkqLC$AQIfQeOaU`y3@qHXtZi&vA*oGE%vcyR|qK9bO^givUSQLt4$Fb;} z4GD6|@`lUGM(p;lBBe98>rt1?Kzzq+t$@DBAwV&a53wbrza1~xcT^rJt)!E)uz~eU z(3p1L=Lma*`wp7JLhPqPVh9SMbJfeH z9s1QFh80(p()t=~K1q{YrzHvc6Z)P{Be)-~#rBBp*bbLW-PjBF*fm3Pm80n~aB_q< zJ9X?`BZC|u4}Bd;A1Zr#dT2tR(oJN*2NubjaJ8V@l|Q}WyUv}wI@=tn8$Qx&j89En z51q&Iqg!r(ac|u%cK7jjk+thDPENeaBp+d z`PdiP`cB@$-(~HC@+ZbNoCiY$cmIPFT@hT9Xq;sjdkKQ5nGHOjKkr+2AGe4?1hOhI zcb6@HG3%M?XwsxXY)|+Vy)SRtcCxfe*7f=Z00l2VByGh1C;Z5A;`$@qg!cM8sBYyK z=_!L&tmjN^n=F@tZK|pN{$c+YtJ^(e{noxd*2EQ;gY^3kjMJL-y{H{jB)Z6pQ47I(A-;Sa&o z7Tp~~i2eblJ14&DI(xz@pvTh(dDb{~3;(xRBM;Ch3%XIc?N9TFA zbxm$vEz_n^8uyD&ki0;4z0}9PcR(j+t8&25k7WZ#Fn0<_r09M>3+W;yxcMb$|BYEj z1E&ecD8*=QIqK=-^J-V7>+e^g->Bd-PS)L3F-xkV{nM1C*G5k?xt;v#;r0ZhV?{E( z{;w-yu0u}X&#azcc!t@SiLpI2i})pX;D_yF1w^XoC!EXys#W@jo^jtV#n>dz#6>4|)D{wSRq!$T_#1ii?%ts5uyEYX? zF_BNdXxv5&C7lkI!a17um}b<9^9%E(1QR^ph&Sp>YfiJ|Lq~i8wpht$!#D*x%nDF1 z@V?y;x%aWAyn|50!|5{bB9NJ$Bk{>;dWpAA6hI>&>d*$Z(=5@2^cCF>>urre7u<>> zdWAAaRgx0X*z!4JlsL-D#5A;kD(2p+6^?H=Dtc;M)GS;FPDVAg!UtE_iUp|`S(iFj z-S9uIj~*u^y_AWg-YXjxI7L%5@<#uSF=&I?V7zffUZE(FTU?eRbFWLl(d4ecpI286K#NzS0DEoF7 zTdEm1<`y4um@y`KlH|{68_*r<{KkcfUw{83ja)7fo8;Tn;2YyGQ>kh7dhn|7wE;OIMM1D|ZWQW@w#s`QCElgV_JZsco zcUQY4&$sYXJnJQ(XTbI4)%$Jx_4g2bXWHYVaope$emUYlLO;~O%+nLtG7GfUMq>qD zrAtT>o`OgLf+LcU!bhBCVv%ndo9TClk)K;NZKhbKeYq0ETITVKTf8=AmJ-=!QaO3& z{`&lucPE=WxUrN>W8LNzENL&4i1*pPsG}r>#&2{9``>8x2X!PaTAW(`%f4AllCIMz zaf15W+%X0N@ADs|hS40>z`31cLZaDxY~eiw7c!_~XOZR#(FKYg(y()+1^H5HGHx8J}?ZP`x|{ckEaR7MXThbu%t3q2KCHpJ8hvDJ!%3B7y88C{n74T=P65 zWM7NFqL0rjYulCOX6OA?{SE#pg-I-k%s$n3lsP zsyEDp*Js&X9pupvt!UR%3}DRi-XHC3G3XTHi7mSYoDCpm!kT%r!--n-87m1XXt?BQ zi_7XKiA@`#IN=NmpH*dP#_VybGl?S87LhREjwA-EO5GQ%4&Q2feh%hinKkTivBA|9 z$0p*Kp1NS@sl}##V=ulAkU_5k1K{CO)UH=lDJl~fHE5`*D+A_ooQPmA75SL=EpX`$ z^->y-W=8uYXPp9s9I(bSVsRm&m{IhLSmhnzftYV>HaJmcX4FoxA6uqU}u#T2T!i{IaRev23DH)tVHjE(8($&m&Z_6-cj3gIk_;22-N`yQ2NOkS4%lRuu zTI(W~`SuUh`Sr`}NX3vObRv zF`YCxRcn1`i^yrKeGvaByKB4E@)a$!BTZuJ8l|2iu$!duyr@K|TaLvywQNTr565d1 zHI+FppS+zJIN0(Bl+Rq5o1bnwaFhgIcyfGOdGn@zvX@dHGQHWcKGWAwG8ubHYGEJrW)=e7H^hVrZD7}kI~JW zo1ZRI?W3qHwC@YAF_8V|n&mZzpvsB3Nx{L;2i^qD&tPw}54u)9`++{CiDP@U%x@ zS%vk_66eTy>nOko0`p4^zGxuvZeOL73-kiUY_H#3bI@)nSsje}^ zaDCRU9?lSN_jmM$ zt2ELriOa=?{}G5O3@pL#HugRf!FmqLGs|4*6e%Z~w&5KSH+{QU=N?1EYH`0bGZF>C znzyx5c2rVAc9+|rS>;U6R$!Og{RwMFx>OS8O5B`&4|bUEC?ZQj78Aae%(^y3{nZBB zh6>K6u!{mWd&TEl*h)afIT`>V_5qHbP(WI-aj_i^R3;x@qv~L5oB)^G1?><7o>#+{ zK_vTwVFGJS`rClR*50Df4>WL=#_&qAexKoGZwgB{&ByiTi_Dx*h93z?`QF|{elmmT zQ;f37Q>hJ`@d9U8i4y(M@iNHhiMb-7z##jno=EIa&uWynxFh&+tmnAwf21zY_%#=; z0$Y8su3#o|38wNaC$P-|F!IZSf!HLDOv>(qg$bK>gLW@#k7oHi8N-*@zZnB3NrX5# zDwJxBMY^XhZRob0M7BU^&@xI6$A~!vJE4neqbYkgrk`8WcB$zKQxE0na$^IK7?Tc^ zW2P2o!xDa$vjBE`mP~x;Gw^$Fc02z7TB`yCf}xw#HHLP`#?H-rOv+XjkHkP-`FGnk zqU{T2F?7{5S7DdOBZbq8m|}l%jr1Oqgt8c1UaoRn0H0Nv<)oS{)d?C`SbCPKN7}F{ z0cpo14_{s_lI;h+db%=7is>-rwn`nie&g8Z87Ogs_as?G0eF_~jAk|@iny@8k{xoR zX5%j)!M{J2!l5S2c{#&JgZXl1-K~DM-$h%xh~BYlu``x1DW1+s{X6$rpAjSXuSgAf zz)!3crU)Y=bl2LoDxAEUJYDdXWYqo?d{3%80PLUSmB}(_$(_;`OXfF%<+=4$%LK^q z5?>M!P%o)s3F9IMj52if%o!OANPLLWlSSxQF#y*Vp#S>NnewC?W2TyQOxrh$6S+7a z^!asf{%F%quarV6yLYvac3wIE1ETx2e!c;0CE${;U`<^Sv4hP?O-oyec8=|&@6Ub9 z9IkmA6hK8{sTfFC#I$xAdgtcigw{hJIwlg;(c2Vf`hqddh zQT!x)*Ffwx?|Gts-5;Y!gl*;P2=`EH4}CR+UDoCf zl<4j(SU5n*`yjqQVfjR}={Y(p(dB$WZIprz5A$Efd|5`Y@N94F0FlFlXb~IkuiFY1 zqg50sn&dlc#N=PWQ@qnpQNJIn$Wjw55@2wRrdMwSi%L{+Bu?LJw{|4wknu!GLg@wc%bc^MTp zguRsS*|25gadFO?^QL9MORcw?0-5ZydXw2iL$4DX0#3|(Ug)xnV$PvzV&SHW4Rv1c zM6T7G=7-9Z(D{)ZE34xSp{6Usj*3US6 zsel^*_~8=7%(-MIemJ&KF-;>ikh!?wfRoJoaRq-8#B_F>Q)PA{#j>^{W6W^Q0h#NO zB3)JUbfbAugD?t*eVi}F!!YN~bw<>?m|Nyo zHya^e$L|^tWhrb%p`ucriw7p<&wA zyo0~fS-w$gaxv~`c@vVl#{RBpTHNuDm%>p>YHFZcL(K~Yh8TXFkar0rB<6jQp4PK7 zBwKM-Ht_69tawjwR;-L`bh#$Q3MbAR?#^mBb{(Vi!xs|>cU7V)S%2s^7SU0~xtY*H;j1C)9=Wq1MH{aj_u=U~39ejM!2|W?Ol6 z*||s#>}?elJZ|W8w{D<+SouYVo$!>Qt9*2eW;4#lR=edkV65SNzfT+=5>tDWlgbMT zeArMH!K<)cmd9&|zMp)M`|B-lM_^cx+V{-#7OeRKXF44q5*kSUe+gt!XO@dtI4dUcmtiJkBKV4P7}{O+D|Tj&`8=jizjB?RZIn*}PLCC3gz z&T4*9)ABPk$d=$L^h9xA9H&9Nd`Y_JRk$UqpA*8;t(NShApFD98!8p4XE!rvonlOc zo0-{-NUrEbh)HF)N=&NOW=N<-=1vi6bkwO2dm;5RX@{%YN)nZ`L7(Y+AIUDrD`;N@ zFDe>{`1;CVLP_wzu7a+cpQ7;n_yYIU6G0P3?7HmC9hJ@FM@{Pa1~7b!sQj7qcYp7T z=K2d6kRbxloB}e?!RKoQyHO-M)`pwuvS58Vk>=g;aK{>ulLG%ulqD4Bq>3+3Pjs{K z?efhyq$@a^yD*ddG`kM@3eJJnpLp%msy4wPf#iRdDcQId!FIBsAOx>?{`at49FS6~ zHEA82jNL{#$6&wL8J-j-Y{O%2UMT-Em*=r?M8H+hNMJEDKMOUS9ehhlX$YOG;GUZo z3_=>sV*hMZ)S#71)_eIS++PU|NAm)Cyd+2pZ`%9lj@9c7@MLT%37{K=d7gNq82q8R5bCRZZld_@PnJk{eAfT7wWI?|*I&uM zaN_shn6~szDhY;mbfhaQH*a<$0KgO0t7doPgexgnZk3zO)O)Y{B)}z$t~%bx7L~6A z_i)UA%!Izs(D!@RUb`bRKipLwXvT0xBM^|#E-xF;0j8F3-+jx9kloR+^oR#B$%q(w} zQTSPUuVO2^CFwW&d;JpTEd%=du|z49wO@~?JvUxxyCa!>WbKcxwe@X3NAEL!zj~B` z1j?`OZpbB9n(XhbxHqb|#hJ*EnP8m{?`Y9rGH!_Zfg%KH4etbXyfbWhWLjOYwT<28 z63OoQpUvo826}2EIzZmj6nuPqJaTQzM9e`A(k?eZUdc~>JOd<-Fsickjk9rT`pKct zqCnDW4UOEgP&Iu*el_li{qa_(@OBkd5hn9)u^iCXQ_r&@Y^o?JT5~~!v!Uf0vjrS& z=f59jLs`iq%}_OTa%mjYo!_cMJypQOM`UY8KSn4Qe=$29)#4gW8);0kWA1`x@r-r=iQNZBXWvItOd-g1h{SfpADD)jv_UMTOSgx87(b zoZxDVcVt*&a|2wet zH@CA@B-P`L%f^R4j1)13F879ZzsgIs!VSZrw_8(1{it~=lnL;utktQ0b`pVi6v12Q z*^8k}!N`8yPF3pNtR4wIjmR+R3nvSFgJGYaa-Q~&y6Ql?eH^a+T*3Cid=Jxs1V^fUSPOJYFUo!df4tY%IadOqt$h;2I7fh@vznV&hcLgd2&rOsegWv@QM zE{0r{df&`Ep*T9n^2MJ*RXt3JIv6)I*0!0CI0sVAja05Omr29hI7_@}hFa=CzR#2g|U%)C%&1;om86BZ?n>l=h=lm@hnD`U9h19#d@fdBZ!^x{#Fo2mp2U= z5(j4!I>)UKR$nFa8&UKOwWns2j3=j68g$ppyFux4F1{q~&uwxEZALBrJarpF_m zq?G$F%V8;Ag0rwGAUfkS6j%xo-Lhzv!h71LGcp4wSKF*sRrYO_PtroOECbEyzFO_2 zrTy%4mrxzZ-oa}bXh&NfQwbI)icxeH{*`UNa%37;94WJTW1hE$wPr`E8vDM&xLm@; zospw>(zBFO`!gZ>E9#0W$|Hc5X?1kNeaj8+rkkyxRhAj$T}*lWa$TGt625PI;xcc1 zwOdTTtjU;PGyqhu!IFG&k8BVNv=+p?+q|F}1lmzxf_ytf_Cu_76;T&Yx3FbcuD6Jo zqrG|3blS}COb#)=HL`E#n|BJ}oEjK&95SgrGRnyXc=>4;0Vd^C`A{R<7qzgahL(o` z*Nh9VWEy>AGD~d^TRkH3?~4;9q029dl0o$!-G42BZ~eGMs*FTFj#AU0=F`d_5Vp0w zrpiDyY4UA%T7W=1)S>OX`5X8UE0y;sCHtpsW)HLZ2Z|S+NvvN!z#G&pfml`^MFlHd z6esuxi<5{Zo~d(fAANbnm(%-I39I+rbaP6!KQ@S1&t#xO z!5+UmVkeF|=v^t`<79j}Z8({XE{YyXfiuFLyR#YJ@M8NpVY-i;W^w_)ACZ`IY}cj{S!bfgQ?5&s zq31(L{&FI&#_!7X2UwY+U*AT7x-F`7VZ@S`DyW&}Vrx4ey()ot51Gr@SsE(GrDk`y z89#GCe*q}*PUaN!PFGeGfQ-fJ&SmCb?+>q`jfS=6FI=poN65o_=zYf$A285GF^RaM zg}Z|8*3)g((kxMZ+9nhZ3Hnn{W5;5xge?@NBG|QvxDBB?wlWT;i^#uzELwClscnC1 z*4oqcQKA6zPb`l(c)6!5x`frcx2L0Q&kFJ`H9^X{s zK9zznlZgJCr9h#NV?2z443m(|w`)*GX9LR7#bdozuHtH1nknaP#cyh|Kv1nQTk3}) zb`b!}KsP|x5zteDpRpNsG4D0Q<6=xP4s}!rsPTM#6gVNKb=@s$E9R|>AS_j|Xw+R)l z{A=J@1FRbrAyq;ds}}tx&u<#wz2Ukg9b|x%0u0qNhqz^RVwK=x84lumt#RuweY^;q z(@2iO(QPCh%Rz_eWPHE*G%pheU8e_2CJh#JKNuMD-x@_JxK>#;zgk^o?;vSsAy5To+aIK&MBa+UL}~{`BV>Uk#~-87XWez%K{r z2{S>yJw4*YOz1W93Cd-s^hsg!Rrwjiwd`kRGMe6Rs1!uKuNoYqTgR$1TTMHaP&kj3 zM&TJE0~OE+^XJ{=B%Aq&;=xJ#(rku8TJ>woOga=5!2#rQu@~N1p9zCA?|S;*dk<{> zbjQo;A)%b)ZHu8&3Th8%ohh*)C#bBQw~kOI@#-r*P0wcvU-{oQC>@uN_C9|8CF!QZ zVNtgtp9K14mb0wxW~W@DmEP66mQ#Kj&DBzdCeM?^EEFcnk~I_abc%2{pN`XucC zXm6n}PDV3cVlQ$uCI&fF=5Hc%uwn#UZNg^~_3x906n`!Pa$~^RyxqdfZ9sI(*oPLf zQ|zY~^_j5JhMT+lz$$Gdu~6V{w<;X!GHhpA^M-jtz2(8|LZQHuoJwLZoB`9nFb{3$ zW4uqRHtJDN8Zrj0us>4`Is=G;`Gk#zSqC$P_?ea_E|<4QNO`SN!czVj)x91pNo#aF z#|nD7f0I!(;{A_SO+f2M!Phb1y%N*hv0)IK)h(?u!IgAI2s&7BYZ=|u8=DCtQk2&T z%1a?1MJtiQM{d3eci+}?e7qc&&GdKLf;cV;p?sVSJb1^Bg^z^yu66?C+sc5sKlq?F z>&9*~70O{n5i@+WPo>a)b25!yxAr11)9A@cm2jK48j1(&KP9+AYgRj4ZU~NaQ1cMY z7nx{}^S_QXR1+rf97Vm%H~Y_l;hS)wUJPDa?;}c^Z@yUPG}`#AWjb8}#1mDHlQyLC z0Esbp;c(V7;N-uy9l2DlKHso63ehg5BYWRPA@GxEyw@ywXEi%KZd`#^vT0(sbG&Kh z3SX(-yvZ{yf<^u(#M*BRC(*nDTLRXR!qDO|Vuo&wEJAtut$o%%U*99!<@Dpv2SVO zBoz9K?qaUEc&~yQ7eqBJ#*jB~?-qn#xBn~PNQ^!`+vZ!#e2!W7Z`lPd&f+1xg^d=8 zi#)RZn?gVhP4k@)f^!{tshQZ=sDpZ2XqGCLWPY?_*A{47s|^T4O3dt9RV&yQl`-?v zIc?I?od=!fG!vuVytkZb^xZWl#!MZXTl8))WTbX3xZ9tQSwlo=FP?XnXOOG>=WCm8 z-A^7x#w~11`8L2TAh9wE>Ijdu`u@YuGmPokUzEI(G&rWSBw}yh;hV67JV$>70r1eD zB8IQ9JoiYfB!R6Qr>#}|N_z4-w^FU%ua-I0W(Y$ZAd_dlita#YME) zVryk7zgLMFyUUB796VP6>`H@EU+Y}b(*pUK6x}#jtxjb>f1UdYJFY(kVO^+R1?%-C z8~$r{k4C^J`GT@vss|&1kb3MQ$kY)6bY2*gO~Z_44X6KV~p}@p<^% zkcdxOT-Ff$4~ar4&K+LVeeRafmyIH++Mom0ARP;rSK&KfrfAsiiY5hfuFP#a>Bq)j zQBIE&0Pp?rAT`awEdS7SX@TIGXa?J33^ruvMR&H}vEB**0KNl}2NXkWK$?-geNA*7 zgF!&K;<}In8~c-6a5W2iWkqUPGrsr}j${DdBYg`oCdWo@)YdQgF3r3~WkUJMZOTLU zKcNj8qn~FP+DZOlww#d~9Qb`yINon;z5YxhEO+{@C>cS04tCN=i-xFPfw8O9YHreg zJwd~)v63LS?HtsKgK2LQJhUCHKQ9a(s>^gh zp!HXvZfq>Lw9`_UPK@I;z?Hw0DTe`uIYMMyi}E@vwBco?&&is<(n2XPV}ZGwi?Flq z3OV30?&budbdTK6{_#`I7o7odu=&e4v{j|ByxGQ#w^GjYbmFYgruu)fP2bQ(PsPyi zW7~iEvAMvCrZ8GZ>>k_Xm}n~><97+zO#sUIuM;2Vy0Np(&Zk_A^QFUm$K&ywQU^aX z#V$5PN5pGt8VyiNe#aHk%XGF7jmEtZD_@+?G$V4^(YSg9q+Ztk zKjYhU1a4o%R6x0@ zzrTyV6F>soG!0z$02ymmCn{xDN{-cBoa)I3$-%vuv|836!~E7?R4OHNaes9wQylC5 zDL?>gtaiBIKndrV(<@Zg1Y~7r6|Z8EiE}kb1lItR6f?(B-8b_JYs_R&mNJ#}@E2)J ztyB(VRrgrz%Hrf&(QJ`N>)oH`PPQMb%6_|-U-)G;`APOT1JG!{>I9^(eip3kt*5ni zkR`>2>=cr@@W-Z>19BUHku_44_mlq$(cgHwzXU>!G;|0J%H9#WxJIw9*^BC;v@b5s z*ihOqeRa5z<}ueBSwiBjxS24Z#E|HUgvWH4fjO1>_Qnk@aLiu)^B2dar+Pgs6yFB9 zlG?3pG>(Ih_(Sd!)v=Hy4ssfo(jii;t@BQS8c8P<-;mj><>v?_+v=!J_*IC!`R=>c z0xqlnp{0uI;Yk7uZ8HaH1VahpL|QDE$yXMvM%l%Q#Q3F2Y6BJvCiQ`YVF%=rw^ch!K1@EmXImf_x}VEgt5c|Es>9@X49F#u|_tf z&*OX633uh(dg7I5=A4&=gC`IpqVX0<@Q+#x=Jj%Fu8o zMv47U3^$n)M#K{H%>rhYhR6Kxe|!}m)!jzxJhcOf2H!KlUg)!EWb|F?N57#C;^!uW zjn=s&S6y%)Vl*A8X2%iX4cFhJN!Jx7n;rb(_G+@AeM3iy5WOa_-lH6&?$C5EzMIlo z6^Ot7ayqBiavH0*BlQrdZXau|c0M@&;F)#)7M45$@pO3ZgReBMtL5o2w87OgpNxHX z5V;03Mi9z?U54@I+**V75H$TlE)>q>=wl-PzE`fUU=EP53&1er#R#q!J)TP*J4q&A zerv4vmrED9*H}RMe(QAn<4U44WsD*!ntMEn2y*!zF;eOKnu*^X&8o46MqYt!wYaEJ z{fd!uGaK12MqTXAV(dh2OUQzIvaL>dYJY@vdAx6gO-{KtqBQ{vQpU8}M=cJRxhEyG z9m_URUF#ZjEmaau+ArZ4;<~69yklIBf8f3|VfPMUKeg7RcZi}Jy*oI?ZWFR8CAX|_ zAyd!z)?WS`L-1CFQ@Q%N*bv98uwlqD^2BUiaD|A1Z%Es`S>@+{D7A7P7UcfysbkaS zt-u?Y!{qZ%u4Vg+*Y0{u**G*|!+$iiLNufwj$IWtNbhw`&Gi!sz9na^=_g5W1tKrLBz1Su&0iP}~Uge1w z^E}1|b$u-mEW06fJx*VuH{L-r`{d)G@n-Gav35r2&j6#?dAVb4;pkGxcrnjy^E-w7 zy2~B^RR((gC-kk4!^+Clui_lBrG+rC%gbK)gDea~^@AVD& zb*gBLlH^QOn4^?TqYjCXT+0kLuP_k>e%5y2d+3YxD(Bw<#q+#Yxwtq-HH+b>Y3+Ho zMN`e=ES%$JXRvcX>KujNfW@Rny4qBP%<`LHbVl~R#>!qGDw3(5Ea642WZ)DaXW85P0$k!5 zIV^#zxJ4t{hW|KLvo!d=RBf3pdF+WgZQ;>!&Tvu_JnBU~qsJQWI3o}m92@jsG;c|9 z8^UdZSw?GflJsz7x!rat|-?Oo)c+z`eump81vzg0olN(NyB%*ya4LOx#Y zE?6RxN0hWQTjxBHW708f{=-?yo2g0ibas@Jg*--6)}r($v{o~bFJQYqX=4Fsdde}--T)scUIbj_hj z6n{z;Zu#*WQPXf=p)}5qE(8Cw&eDB?iV{0%4K9N0>0~fBS4N<^`&k&g>)e!$Yzi| z!>V#Ihr9v908Ps-#H!_8H(u3L=CHm6p*j1ei&Ce}_ct!b&)b)2qX+tv7B(6x9xw!kF+=qbeAZ zz^GM`nIvAdDaK%Xw@-)gu@r?h>zEy}zjg5PNu`Yc-q1dc47+fM%NkCA4u;-4-XFE_Xul(ndYL&Op|1p3= zT{)l>MjW3ZQS1O^jYk-(Dn`AOZ$Dl7{AJo?fhPx@oxTNj|dG}p<_p7aJ?S` z#cG`3Rd<)vhTZhV7a%{?C*8^leNPt~BmYmKOBw*#ZxXp8&tKs!V-JhKQO1!g?T&Y_NpC3QNdg|pU zNi;EWvw!3?jxQ#<;McYAYXF~^QFbGEt`_nIaJBxyYj#>zqBleM6Ef+l7M)Mf^Z%VgN>_LhQp-P ziN6}OhfFO^-(}jAboz*9F=khXvRB|&S0Qiv6)9YcGT%lGEd%!<-+)p6`F}ylXucn* z-`hq;vX45;Y@tdSGat5cKC`-mRAgYsgoi^pBKP*X4Ijhf&RcDB5*NL&4z8z%=Px9P zO#G&Z4RytJf7?Pl=V>vImwdt|tT7rZa`B zIsKs1!lDuGw;C7;9k?R&rWZvZg8m zq|R_ICURHJs{Rna-*sl8%o$d61%2Ep=B%o9Zv^!no}o#Nyz?BPX*Bu3#~p)YClm9Z zBAr;he6YDW%quVq&s>^F!f+UmOe-2*i*V0Bpo0p?c*#P=buytZv@m{aq9;-nNbI&l zX*UW~Z#Vheqj$jq`zGJ2(mmibl2-hajj~Ql;-2dlVFjd8R%##`#+k_!Y_*VZQFE8Nh#gk z-6h>EEg-#gcZVR|A>Gosq@*a_wRGnK(y8z8{XOr0u%F%8nR~A5JdXo$E_)e&B@*6N z5fxc(M2+}ZXBq*f*GkL0-JpoUV8<@QL$$F(16hw)olYdzrNj&<1F*vsVX_&oR~cEf z%@K8sHyN-tnA9aPR-t~aU1U)&J!mNFWp#){bCz^ttQ1Bv)%(Z)kxHI$zZ0)F6X&zG zK%GPin*air*e8uAM!9COq_y08DzZpim`qbn7a5*A?ryqq1EoQu)qpkBIR_)}AL+lj z^M-YmP%&;e!G0p)=RGmTy4vYxLb+ta@VTMhAKRS?$AHWiL7W<>AT_z@gOjHLosr*8 zYtIFpNW`$kOe$f!9a?)33=imRde_N`A?Vmbxl3fKH4oaYQWtQ^>ECGYR{~j)`f#~h z*A2oz_(V%ekGh))(HB!7s=A>|TjtBq^U7GVLZn7z2s>bH-l^H(K3WevpA)DTxu%sh zXfL%>s1+jUav*pb-_wtbUTdYBWAN!IN4UFqrwd-?%U(s6`S0X*ZKR{KdqJSMpsiT` zC%gTo1$(t+fguKIto=O~TI(5cP*VxNCpTxqNsClVnXVvX+evVYa_og>c2&h&wS2r| zaX53D#?F;#0q@(OLjQfRIGkE;OjgUwbyrMJGna!fbrg_*z;vGutQM4`I)R*6rsaj?r?hRIYzr7QBNtbvsVS6hxpHnt14 z-<3GfQsrffo1sHcbQy$SgWj?BP_{!xC85WU75Qjv{lWty7OrU;WRoQM)gNlR&UAiY zfd-Ga=jBf531~8%+_~Ua=%ib1jdImNZIlxAgBZ88+bAl67bW1DVdFwV!WHOgq zHD`M9b7kesmX!IKEBO5&s5=oydF+R5MNz3SvKq8*@Y1O~dGTWy?%0uWpBiZca>2Ec zt9)xAF1gQUH@iiwd8;3Zl{)F)D@CGjiHl;UYK>7MRJ$qTVHfzQ_oSas5TqJ9Y&`#xDys%_bzTmkh-BC27bR=N6z5O>MhUC4W}L)D2BVpQ+wUuZHL?GO&CzdIgIacZW9};LZ|!#s zph?H&swbT+$D?Y>Du-=tkncvBLGB^D@=%}P!!P9+C{?!WyF6a&%stgBLS|4lbFvR% zcePN2DmtCqg~w2cI!v4keI6^r;ciW}s!V|KK*y`eY3j$A-prx{9p>fG7{i8O1+qxp zU*9ztCL&qQR#tvpcFm@mp!$V+e|xTR+X0|Crd}&p9Ff9lQ|(iA#wV7Q@IaGD)>sSG zBz--rX|n4X^Q;J}&!|$(d*TcEW*P@A{nKz1K-Uob5q1ugGY|UZMJnQJA)@4A{Y1uj zGLuw|Q-b8Yp<-;$Epe2U_r3s1n3slwmMNsUj?zuC*X#_Pt^u{2`PkqtwAV6ger7&2 zFk9J=J4OxeR7x!0>wh_<#`v$L5@GenSxt~QU;oL{wq4BR+$XP?!F5h92@+8qO$#kn zi^|JZrC=zWzdZ^W9e^u*L-s;MjkI0MYF_;SMs(YXhE>l!x#K!3({?Zc0%eqML0Z_Z@qFf&t~ zF0NRQaCD(qT z2w+9l?pEV^ZgoCIXqBrLuqgQ-Yvm7}zx+Ml8m7CZ>EOjt`3yf={veE<*0Ijx`m26b%M~LQMW2B~Dp^8Q{EU|A z_(f)c$*d6^g(d;o$1e6S=nvo8^YINdHHH|MJTI2`(*jI{+B#Yy9}!~A?);*3xF?x} zm>HI}XH%%p9!Dby|()%;?h{D2_z17PJWz${(KhyyW_p+^p_66 z7yx5opFYcA9vdYMN(UmZ@mKRf`SdO@62DDzJy}m~BH=C9Q22BiUvmN=D&AZ@5FC%3 z1>tAnHbW-FqCL2{X{vtMoo7gAkIzEHea3SZ*h4-PW>t6arc$d zOAB4rY3mSTg?y%7A$&`#F5zK4Y^waQ?|J7(`_8t+kZgIlq4itL5W|e2=M&)Bd!^7T z!Sv?*%V8fN^zS=>SNA^KrWNt}LzU-uCg}e-n?D3ZWG|@yo#tP-hE+Ktg1F$na7C$2%1oKz#=__W106jcal<7x@%A(jo~&OM0vJ}3 zfAH8*aQ%coblko*9f8*uA5TZc`#kL`zhqka3#}HLX^^4(Etwb6=TAS*2M7bEfw~${{9taf6391Hn$4!>3&lfdCUoMISfHn22#Fr^Y+!Pg={zYF^c z@qLAl{{pUkKyg##lrEe}i#QXcYxY_0e@jCxrt8m{?9Xijjf`fd-OKNwlpu8y>1hY& zaK@u67?h}l!Hh^vxe~}xYECAuDSI<(PNoXGWklX`&X`yX4~)-zB-vEAn3hL#Ma?PM zk;KFiQ|~_Rr^t9$o<0#nMuaLtnfe68U`q7+N~5!O*-7epn9MO{;y3Iic|gho5C^=x zqR;^5Owxgmk=&I7flmm4f8Kdj+c1B6Pz1QYz~5M_XOo5)?a&?bkor1-=ar4Pi6{Hz zgzAj?T#IkAabKJNpBOn(S@(g8pA-*IpeBB3It@%`sXPW&jx;*Sh}zp;J>}5t1a_>E zPQz*izNwoop+`g~SWQY3QV}{g0pWRt7&v#0pxmDP$( zI5Te1;8TBk+8H)L>F|*sM(wagL}RF8iXo=-sawfq`TA4p`A7R@@|0>{w_3^Y{}hb{ z(&EyNP~p_Jqmo3(_kN#lhy%z{zcnRNK}J|-@$yYNM^h*BugF}z$L?&Vj*AmDl}@2& zekqmNp6j_a6p3beZREna4v)FSH36L`-3^L-kEE1vG{k=j54xdzItxEeTGPUOz1=Fst1N{zqv<6Ie`@SB+7ubzEh9nE{|2)PqRrxGsX*<%?6l0VAOkRu~VsnofG zWXb96f|v+!Yo2MtdO?)ZT+;PbbIooTM69e2Do}_D$CsNaf&L4ltIW=xiI4uQ3-|j;H8*)C)pZDz`-{kA@P6Ch=R?*vyoKqw z-!*Ssq&LrTJ9LDCfAXwA#o5J1H(&k)Dt^vxw&Hmp`l|nKdD{Q0#Fr{S1ktoyFC_?; zQGqN#qGZ*99RSf|a5UM3d9>ZxDw$h$zFSQ3E>vsYePNp}ie*oK=xtrD-+?~j`}ece z-4x92Q(PKjhtfv+awEEa=zzB}?Z21t;4w zT-qLYjquCRs5`?00krWlOpYD;mTX z?YC_f$Nk*@#6rs7qGKIxPd+4P#is+{I{;G+V7_;MSP$~zsmz#e)T30dVeA_@U}@~U zpBeucp7vXjXxw&?B3nHv*NQFks?!*r2%2f^YKlW&Pz`U6g7)=&^k{Cc9Q!*Zi{skT z1W2BV7-zS3&8D+^1h)cjb5CcF)6418cvq|>NY@|GAN};NYUJ?_ zspa zhQ{%k{qP9>W|zyFGqWo+S6hH#y=1DEzVq3S{`*(?c+T~H`#Rg~qx3V8lWz^Ct5V|L zAm!hB+$L~`Bz^38rPaUOEPrv;PmlI91u21=F|)#VIcimeLy`Sr`knI8;0q_m-&t5? zzAp0>48(WNv{=QiW59cDE&NXam9g!{*C7!8xr=anlhwD?57QIXt<7Bt>C0K;t*(?y z!eTWdS!e7Z7uGXu^V@dyCX-8S(!s)dMG7E++_+q%l zL6m3jy=ZV6*3B5@eG^cv(+n%ARNbTu;{5!G*JL=8t(8uIbU{6>fQ|O8E_5oR`Lmfg zm(FOrD50XmJI%2X9c?!3UH}Q_C4OCcRNNBfp;!j2l4Jn%q6FIFVu=TLFqX*9rOn3k zkb_y1!>-S|Y@?zNG)A%XvTn7D@H7a@0JW1o`Tj{5T)Wdew6Pw5*K)AW zgsxRo%|d>3O%cLPOz$KuP%m0EGATi)n~z_0&iAzb)8q-)ZG^jf(Vxlghi&4YW;dh@(i@C2+%z?O*J757 zDM(58iey?I;x@x^d2gJNoVxszZD<{3dzwj#W1kQ!k+f}fJ88vxt@cm4P001qRp*tQ z4&;T?Q?M1A%19Y$oW(#m0l=D?fL2#)@z1jN)%1^LJ6>K_aw*0Kn2Q4+l9eyFMB|Oz z+eh}Xn31z6Ky*w-BY{3N34#M^sbs}P@lJwtof2b83E1>CNxrk@)^H_u}oj!Nqq7xc8@4Gx)7lZ!_aJWAuxaTE)EJUygM zM0fPIlN-qBWWZu!-IxZr!DH|Lcfn>Jy+_~rC4|5#v{149}Nq8 z*6(f3Pa!_oIA;XCU27O@2eVt5G0%$rOFc6KQ(wkSSR*J5U)$g9@a~w`P=4lzpG!T- z%eeq`^gmL1@`4bA8MB$(4CT5IX=-uT@q}gct&R@A#D^B2;yxP}lWoUVoUO;Acq?|e z0@Vs|Ho+gqM2HO}X|D0CSOc*cB~X#R3e_?z9z-Ena;cYP<9rm@ylsRQTkI8s6WFmZ zIosu#0kxhu2obPtyHLF298B?A72~#s<=U`(Czrb-tN5bNlYK7iY@gD6V#r(iU!4_r zVWlliC43W#4zF|-xtY(^4eNp@)a3Y)@`#kyCe{Vo56aLjoYiW!S%5O-AdxHPS$&hr zVOxahn_sux(@2X;w93cLA*(^_4`sFp@bB;;vej-e&`oPyAA4}ww;@B-Tm*F)|(pB zLqhh80Wm$1=IMgkDJY8ESGd9T+jSPfggk!q_hPhvpy%0lDJyxhjJ3>g5Q$YhKZ`m&!GXg1Y zMZO$Y`<>R(2)dx!m;YPjR%^2c^e(VC@wyzpN59DKES=gl(ZN6NC@CFIi$5E^UybC2 zhJ89aXNApuo?X8_7HgC$S`m7S8??K1`e)__mCxY)Xuef#+pQL9ajn_qc4vgXH3rTv z;dUsc#y=b{X7^x=7{|Vk9Cp7#d@`B>^%DO!)7>ePRSSd~?(_H=sM+}u@s4_h@EB*G zqy&|${5NP=#+nOdBPIaEwE zw6azP)+ITg)-?X3OUHY+qH3geh2ci$G`!MP3sR=X-Sx?vJJo{8d%IrwX~M?yf1SW% zh$CEcd9?>l+FAEAugDe!f#0Q-7^ooVJ!#!Oa60zsXP{nl)oI?7*46) z*-CbBJMS}Y)lB?bQ|c!UD}q$^bG1DbR-Rik_+yl5yqZ4RqdoV@j@E?G9_6+66d(7B z?4oW<;L}Q$x+`U!V&STNJ)@E*tH>DoyTa$oz0sn7%7--csHbLzj3MSFTmKDl#u#WQm}=sknz+`*qF?Yx>gX_x&U8**GI_VJJbjDmdJ&8a zCI#vzf8i(}|F~kZRdOT-(An9S2r07JK)9HcR6u_SKv9-8e;JRu_w*L92Ow=1h@1tx@zx@yFe6k%Xz_TzU8H43R zklT|2?7DP5nh31kK_*|mepB(A!G`fui=mv%1ldsU>1OG`V*&8=T#2IQ{!D8k@$g`H zwS(-w_uQP?UhI*md_BjKq3Q=L&C`Fod)_-rsY75lL)yaF3u-;Z}^`tu&=W`9$Vb(_l!_#wONjUdS(Lfne1U2aU1* zN?S<^dPtHhQOTJ3(((cMpHFoQf6Ky|p1HA(OD-hP6w;JBe&F`UnP9Paa3-5|*18jD zss9(DA@Fa<&1P{?bumunA17Zh#`7tWu{fOJavrb1=j?QF6IgWFKk3^5O&IT*t#1LOIWHiE53DQQ~_8V9 z;5tipMuw9{P=M25c6&{7ab8}ZpIw+u1Cp8f6U^tqum1b1n zXU)0_OJQj_GN7hk88p&_Q*T)SXzaNgb$IWS*H1e61OE3XEtwiyw+1QZi&kC3V=e9g z{urw!S*t5ZI1+aA+3oK$(YnSI@eG==+OeYQ2y${m1PN^A#^77}=egasJ(aoy zys7I!-&Q5FKg*9NvMFz}rTqtHy*pt(y%TeIz>XYsJ&*FvnrzKDMsG{ z|B}~co=r5;rk|0VrQVnS*DYjUBbPaq?9vVII^SCEcb#NABYdNPk@V-ofb9?aj4yRy z3gIOp7PcYAyp=20IF_gH1P`leG^&nG9 z?AvdKA(EZsE+KP@HSbPq6x4P=iR*|=_A+a~-@8!S{m@K~Ax~N|;O9RQ!t*=&XJ5NS zJqnMx^f8(wm8~`x{4X-2{%H&(7Ky-{uZ6u1fhb0Ls-pfW93sy?8sPP68h4+Yi;{ZX zfF4Ss6%v9NEZt^0a-}s_=Iwp+2muCIVod`|x$%+ZaWZ?hh65k{@>Z2p_D|g zjg{GmjFBSZ#qcSn6cqbYD z=8WkBoippu?)ud$0 zwj0cdU^~3)Sw&7)Q~sUF4Ps!`QXY@0HYHH}$@t2TydYKiC~jWo`%XGOw;bb@%VN1D zTB&HmlL#2bmukhIocu5K_f9y8(u#y%zWG;UPbdhC$BSCBX}6luqohxHD{RSMEMk9$)y)0;4Cmro_zw7t+MHo~?)-Y9lz{2%Qp4w>Db-PhO_ET*wi?zw8{z*# z6+IFR?(S9JnI0M1Z(2D>C3qNNhKj`|UA4-?^GHg+MYv~{>*!dr&_kkLj%?R=Bhh9* zi#6R7%+yO-U(AKevEWBnx9p|hD>kEx&|US_BNm*O=U#3TtRx>}YZi-8>D}3fkxmA_ z9NzLC(#;?Juz5eV-Lwc3BO+IZ7kI@Vh^{7jLj(A0ZD+njui9%VkG-z6Oxz2?Tg84UB#42^P{ntaq}3eP1DhFyl% zu#%9R?m&BPG5_=A20Y@$pPvCj#8>0=SQdBN-MZf&z=lUIegQ8Y3_!$ka~&ps(ei-r zT;g|vO|q$FRRRRGpMAJFW@>OfVjEy4WWu*4x<;GQYsdLZAsxH`JE;4q9JayRxVG6j9<2R5dC0Pnp&q-O4%-F)f;^;_Kd4j7%QgIzm>@Bt{|~K4YCEx`bIWcT^^C&c-P)I?R&&kW%$H z(TZBEyw#UZx7df3-;rFWo7P@&!XTeMk*u5~;H|UyND>&bnzKW!e^0bz?R1jFN(7)N z_y#5>*uHm2w=YXnzA+fMuZP)3*`c->p8@B_@GM$81iU_3%G+R5c&lcyrWBXlotWhK z6w_$W;2p2tJO7R@Hr7uEV8t*F!25^}B=G0<6Whl1KG zq+8Cse(zxqDKGy`<}5cO*WMX5_oo*y6C~JfKS`{Bk?Cj9=Xq+R#NR-YluuQrnE!iZI8 zb2+%!JwAg1575q=odAUNT0L=-GB&6PXIb9nw45ydp7!5|c}XIu;!<_wg9-mh960AE zsA_sd(0X}FdZR^}f95}$kQT~jrD!EdgzaiNFO$Gr%b&}eqMw3A{D(BKW(%`F>a^^n z@ag_mD29+Pudc6F3y!a{Q}99?=q?f+#e?n5pj}^SYL;VUY#VA?FiV=xTlq|y%}CFD zIoI;-^pudBdRa7hMrEoFq8FwbWH&?`^FI0|=7xuGZKR(N+SWgyRGX^nl-d}hQ_FQQ zg~IUgIq6{;e;^+}d!=!Gf}zP;7MK;JPjaJs6tIbi9BK3{QV2Y)@mvE{a&y*=C>TSD zKbk#Uq=?B+wGn$+D1lPH^WO2#KUiv|aZmVafZ^%eC`6MZq=6{z-OBaZ^ripEve0V2 zbSoR>1esvY_B<)lKEIb&xy$i@51wT^Sdof^@*vrWCRcRe~ z31kJGmv^n^kWYC)$A1R6E0Nzh*+vrBsg@F--KUHhOz^_w3Ot7c2yt^vv1s|0DEpWR z?KpykfPUM5g(p(XF7XSemjC#E-%3f!D}D4qHw~2TYOuOZ&6hA;#Q6l5_O4F8WXi?- z>37;>6jhJM1qS5i&*0xHHa9;)jmbNp@%&2QQb!vWtCNqBJ7O zUD)dvCL&Xk;JkqxE)63HS9)v;|2wmXkwWEBfj6~KFpqaS@BsTu77_b?eSbkjZH=Mv z^y=e#y^e2Z2o5?U1M1?RB>QE|txjS{HxTzVQmP|s4->w0RXoiNYvZn9u&$s$ee!t! zP~5LEleh?*E2lwMDM+um{#y*dY902@;4_ZA1+$CNd@p34pF<>2;GydAyT(v_cG!=jA z0hhYt%PK-dys|B9B|EZ^ex82|6&4YZrE!u|GY&3S1l7sGBY{S;xV0E?FPWw zrZ^_^x(+x5S&cQAbDpzJdv{+-VH1~OV5}J^=#goQ_~WokkKzqUdF&nu{T$o-Lxa~N zAzS;T;O0*(q#t$j^^lu(BtUofeVHZp14jM&DWDgI-r4CdBF%+3_K7sFma@2-iS9f; zaQwFdYsSiT6p!8kgULa58y)`^tLqj$=7pd>S+ zEyD{!2O}KGI$Y&JUC>_lI$JN>uC+4H@?69Bw8^%B zy5CKoeasRVDS}0(SX}0L-Rs$;?TvS8!7tbDrk2YR`TDmLCozjCwrAv?e0fB z?<-zz95^yJH=!|H8>(S4?>J(c%Hu2ABp<04AnYb{&U8xDmfeqC;_&8VZ@qtW1h;#} zYqEFu0YNfaAT6nfGL8^^m&QW>_oLr|$&25NLBTd8FY_883ni`QZHF+9^ zN0WYWt;YqcXBZD5=^29ygY2s;^)DR7L^zuu*xA5`d>rr&+4B)Q5vv%&zS}Fs;&7+C zZ-2XR{ASnk?0ap3K3_KZ6Dqs$A4p3Er@iJwJ@))(-{JBHrcxvXZf_WHECG?jsJUPo z?4T0vkkquloDr*Sm1;$M$-|ka-tb7L@~~yV`nq<#P<+1tw?rpIXE6=-^KS`O9P84P zk^h}gLo^Rh-)7I*1fvW$rR{@lQxB1QmhBS{eB8(}Iy%1DsEpL=s^_NU6i}H<#vIm| zkUH#VKhuxb*3wCa;ime|NWnCckxSonS~fYS$hj>;vl*AY$TUpvtWI#UyJ=(4BfT^e zRt$r%D$ag-iw8+gdA>cDeKvX_nwiYNvw&18grcKSchRS3jM=l=W)zzK_yw@K0aeqo z{c|!Yro&rrw}#bHq1UzVn-?MVAVY@P^L3*XJhX=}`{3t!)-^h{|I3f5##kMSP!v4*5}mv4!EriG&r-;YsBI5rcS zs<9a*J!uM0rr2un*cHWW==f2*KDR)N7kokXMn`8}ua5tB<6j&~Xm@I_nBzx3v#EPL zWcjYy>>zd#W@7{P4CRYkcrTA&G2|WLy<_Bf`(8Mn| z$gKl2NOl@ouHrR#_Cg#Fc%!%COHf2YQ9GR?jNSC5pv7xDTp)434!)1qy^tM(Viq$laaRK->okH z@LW4o{&LwOWo(K_Dc&R^wVZz&>Xhl^8K*8lNxdSEKPGu;j-*`69}6u0s6PJSgr zp<~<{5N||oN>7Q`woO1~%~IS>p;d2+3Y4q*Yc>Yg&5zXKdBh34GYW zTJ_*>Gl_V2o6GIs^8$t6ujVZ>$b zS;fk2cl6)lK`{Va0V^=GuEpq^D(X;^(0gXv9he$D(6due(04bx?H6wk{Dw7Ejq&%Dx6j#UvCR zl;E)yAZ7-7guHcHz2%FZxvY;ve(*5GX|fi**{UY17KdA(iLhRJN`hJ3fA2#%KKAgi zePUj^sDzIAFQ!5eosCT(FRd1cn0`2>DP$hpEVVUW(duM3`rHZM(GBW-@Lm*zhT}gz z)n!EOw&b8wzmIp}lCF8_4Ki^TFzmS`D{@IqLC!|Im1Gd@sy&y~c!+(OV85~DW!F4apn!6hwTubjkJK!xHrt2OYO7gnfQDLro% zlm*Qvi8_`Y%0H#72M1FcGPjsuk*W}uiLBl~T_UGRRlNTuzfwof&;&kIy-+9^?+~+Y zMpSo#wD!Yc;t6)}@D3$LpaW)Tww(IlQ!=h_G8TBULr^Q^t!6}E^E#mm5+q=}Zl0%< z)frrqtrXFb4laQ77>jY0oxSTF;JpTtMZnlPRZ2zZ`O8s<5STm{4Q}<8w<8@1#wU;Z z>%vADmKf}uM9*-2RUXkyHZS7{StkCHEFyIEvT|9(7}uyuL0_!j9kiX^*Oot^3*Jnb zFva?KBx<>_y-F6XmS@}1iSdad6?9>fd? zC0b?QO%W;TkLT7;H|XXGWhH6;-(3nwAqHR>z6ea#UZn0<)$ZeqaD~;rccuGX#z=u)@Tm~l} z@o>0t;mZU5@48}$fV3gZ1dNm`-+G1u_Jow-aPQm|bSJbOgUdRR3!A<+bos2~CE{Al zA?jhDiLYa2s#>6x@4VKuHX2g!{TZ~NDppJNZEM?Hq$fRDO^aV)cp~O$XO$i>E(TwY z9V;jKcvn=lf+@N3YLLl4iS?zUT_HNOpn=&fTvt2#E2o|*D5_Gwz5_2;7kWSrBL1G? z9+29A>*9F+YlEkj>}bFWuzT5dukIJ78hougA!=HF11J=A+-9_rfL#QgI#bvJZ!6e~ zGgn1DEsZ(D@;zpTQgymgMeN*3w&RWT^4Qvi>8ya7nL)K0_WQEiW~x;z&hBB8RqEW@ z8R($ZY>T)7Oa7_=x`#(_b@S>PMqp%uwsXes;JT1oH0Ut%zVljiX8ELZ(RQ zzphmnEs2>UkE?AP2Z6!~&?*7%6NZH38U3TTdtD`hE7l6n6;G=EZ(>P_;|fO^B7W_p7k z4MMa$XoS|}#{Srgyy-FaJ6xXIWfQVYTJ;LX6}xgq9sj!*e*GnGFob2t;PEvp1&a%| zB5)LL8VtBFGv5AHH7%WF*Ng&SdG~`+a_8gH>xZnG`hZOOtB|$v4bV4dN7MEYSmUHq zHv931XUB$$c9x}cBS(+uw5}o-vLox4^oa7q3hJPL;RwyomYr4gk+MM~1UU6}`arA#{h1w9ilR!+n;KC1b{r^G=jqNZHcr%IC!Q^bpZ zt#gB0s|Am!wVJPDWCXVPMrpE%q-q|m&VLiue|#~J zG{!tM>?Hs&&1>sKD@WAnnJ&iDNyswe2CEL@eQ*D|>mZ?Y(1_ttLnwz_e?1M~q?>7~ z@F3x95!XIW9p;gL`SKf{UUy${aTgz_=rjwm^XSLnK~t3NQ71I`t7ed&%V-aE1F>f7 zn-OehvCOTkT1}AKRd@+X>?Y8JR5^pE#qDN2Aw{8j)+@c?>QISOh4D$J9{nQOy8NW0 zOWO(t|M_+Pj~Y;)BLiSY=hG$5UHx_YI@AZdAZA010pI2mmig{*>(0DdGeE{b!3 zOlpI2Rq!J+cH*59w$?vV1L-Z);($YyC+J`}a%Lg+5P>T?Jm9&^CgW$x?Z=}|e;gqe zL|fe)*m+hpyv6P<)l7(?Y~^rwz|kpK4}?+UgWEBlLFFj!oB#UFh5-+B27NbSdJnB= zv1|X9MG^&500ns|;7*wEOL^-L&Rpco% zE;ATiiDk@gCJF5XVntRc@$Ds{TxpgVvI_`}eOMUIlD zqSxzJen~@(9Df;3o+&ANUKuss{$kasT*Flj^8p$OybSgdsl>V%5{$|*p@;^Kf~@YY zJ0sJX1h-BZ7eE>CKh{b=D@fCSpN&y?HENZcpA<-_hB-O+r77)f^o+Wh$pY z7XjDRH1xDW<;;b+O$JUgg;^(h%}tfd!YrPRLp5s!-otQ?!*ENgk=iTD3F9%zS4X<9 zc;kbrFd-NE8KdHD6vqBW31TkFW!Axvq8t}FFpV-2qL>saM)Z*!Msa%fQe~X0@2qz9 zJaUZ1%pL z&&6ZpaiiiUNkaDg-Y9gR;JnEK1D7e+s5oerF=ST*Kf|r#!t})Q=>3cNJVCxFcDM8TZ8))eKa}7)p(l(vW3d}sMC+T2m5%DN#Q~ z03;X#SbAkcN?#86M0M7auVEKG;vVcHm+d1vzHh1ULFPOF`2%RNHv8sUBnm_0$dV=q z&hcKA%vP-7M;}+F-wj=}LKdyLk*a;UVpFb=Kdm}(%4Pa3D-5F&%0MyWBnxS{bVx!H zxP(V3@1E*5ipD}731!=fv%C^f>S$pN6^B4p z7hlzLvZ{5pvT%cDr_mK2R+y%0S|qj{JYwA;n)ijS2l-JC2_3Df-Af<;6DlR`txJ&? z1UIt0l9)v))()i+_tF3|(MpM`vvj~csva|q6o|DD_(Z#U)d_nM{3#JrC( zOK#?fCtrI7R%!dPy&^#}VLal=lOK9)oQL-N@M6E(Qt^b}*bG!^)u>3@Ii|DaqN{2i6$ zsyyg9(EpU0yw9r1#c!HFC(dQ5xJ(9#p){XW+OA?Oo2*^r$j*VXlrk@3y_;s8gWaN; z`3^I-+w)z!KFpTmGZgN`-4~2&#Jx@-X`x8~6KQw3YJtgX8@E$rEQN|jmW6N!mqed+ zlXoPAQv-XCX^fNL<4U%5ep0rr&6hKc!!m}KAWzMa`M_Gk`N7p^#ITpE?rM7TpC zBYeOj2+%Ug7y67R)95IXTjwXVju)%9;pPEO1-sTU+tfHgu~BZ|Y5!}n@2}YL_fXCE z+z~ff7GcAjjnT~KAC;3Dv?*reW0?m%l=XTNcqA$#5Hhb9WRL2dWe~_ZoX0vTcQij1 zi60O5Ww4UHNVExeZ+L=v>eg|@qW9i9X+I)-KbgAr(E5KgeFab)UDGvA@Zb)?-QC^Y z-GaNj1SfcK_u%gC5Zq;Pmk`{Ye3R$>|0=4et=ie0oqKP~>F#r^JLiTz0ReSE1uct} zI&G8dlODXXY0*gRe~3^1A|`m8Tq}sZLqG4FhSMo#`JrRz8l6hM%agi_i!PhT71=wt zpknfCD-6I&12lAm9ezd4k0m({Om%vbT}UvEuD2hx?FOHP?-wCO_xPFfxLX*VKBz&C z7D&pP-1u%Eb1v@{?(&nDGK(7x8F(dN$VW)_qmRJT3hM^dqwQ* zu_NW#HSH~nMr(DxO`z;Cs&p%0~C)NUA z7sy8?3RcYilTLXKnFO~`gUo90CbX=9IJ@5~Xg7`0U!u1A?S%3$NwH&tqcBUJ*LK?^ z;Kjb2nl|xXR+<^Yc7^M*!R%%ktZ@n8n_PoFQ_nB8y(w^UiXwoGu<`mXO*n6rcY5cs-^7W<-^YwE`eNLKTd#AiH*&(X>YW2~Ln$PtNJH!f}M_UB} z##^^16xB!%0!s(vd2uC4NY+gzi0(g@c_($Kc+zBxI4GN3n1t562YH9Xz$+x}fuIB+ zE>GvKD>3ThIn7N?4jY@aOt~La>~(SeW=7)kXtVDz zKMBrLy;y6iz(Y`l9jzss8CrR zrAmbd)`9ai%Um5t0_70a)KA ztRUfd^WKPgW_L(uUpXwi;C0mR4LO%b#d3`nPgieGe8P0$Jck#=a3135^2GTL>oGWY zwDEMtSxCV&R`cNrE&|P2G>GDtjE{1*2MRyAJJiA$6T*gccH8_4Mqb;n{nLRKFJT&U zv_@N#a(DLEEJ!~OhUyv?8u;ItAbzvriW~w1c`Piy7scQ6nU=PD9-?9Ky%!OsIlf&# zhz&?AihRH;9_ccv#?vGfuv^zN50d&QRKRrYkgO4cJlds2(>NzQVq>g5$qPb{6y(pV zu0Z?0>ex{9q^+G&_o!W>Y`=*myv^*uFtboCCu5LbpJ6IjIVsXzF zB!&!C)I93Jxu|}7^T(!pjSNX3Kbea2Py(Lq)N)S-=4;ZAJr)S0@_^5~VG1ei%6h3R zN)Vv#;OQY&qfme)f4~X?Gd!8ZV`HDjQ-8z@BUq{miT4j~+ z6N6%AI505{>AG*eo8wBI`S6baZ$Cq67xOwXW84}+i}`bFLkkw z)1t0vW2~Pa3-Il>?JVG`wO0AFlp0eDxt@Q(JVVTbH6i^@h3{uvGaNgw;Yk1&(zEv= zY_rv3i=@lj;Uc8g#3OKBjg3>l`&$Y3Sy^H;2 zGQMQq38Kt5;267jvYZMT4d!qkU`9;=^;=zQPk{`1{_V6fSU4$Aa#&nZAvHh}tFFNj z9!v=KU-ezVzIAUX@nuv@;TtgC!I{&~XBU=;0~SsoGw)e=*Dn9@vsGL9k~TpVLa_P0uzfIl*~K9NsQ5jR7Qq3doQIPp`l`~8#!WbxuM(6`>w(()5I z)-7um2Y^L}suNsQ*_VdI)bO}awHb1jdkr1y^od&TS30cu0xC-wt#%Kp!7%wKrAree zlk7j!<-C&w#m`{$vg2>mXKb8nCjB%`yq5~a>+d`3d}!q&CPM^R`}N=^zvHvG9Y2meM19gd+QbwuMZ2}HqGm2Ng=nj z%c#(lb?*{e!IK#C`XS89tRLq#X2g#<1Ix^1}qTA3&0UcXf|Ir`GoZ{fTaXerUJh zh8|k0n5~V;ms`+At$6SGkd1WDNa)`jwa1+!XN;V#c(&+ zzd1Yxvrok~i2J1F#y-Zf6m^_^(y>J9@Au_2QvqdC*K%E`M}|$zwmJbD8qkH04|q`n zMl51Wh>kd)75o*#ke&2?Jhs+8Lr5W*jo%Lsa?~2NATiH;QCRyMp=23Kf-(fTTU=v{ zkpyS>w&$yIAmRF3Nqeid5zEU7*;73OgaMK%gh42oT0rkSIY2V``*5;gd3BJav@@PU zm##<&7Fa>6V!Jc^xD~BdI&Hie*n^M3#qI2?B3KR1lQ^mzcGOg)vCOT3L4zoMuDNm>K=BWW1C~!r!nd2uhHOBG+f4Oy+3P8>hVFfj}1K;R!hD>7;h&XXO@(4>dk3_&`1SYu@qtjx*mtBET_|v#7N3hiMH1eNP z=O>)gPzDx7_YdX&zm0wsrKZLfrAzEqH`TnXB5G-Ru!CH6JUghzur|x@-D3Lbisl=Z z2ACTRphj{v3QP10JzgmM#4ViO7CA^Ih8J^b34+01cJ-SW68Wv$S_`dma}7h%VLMz& z(K{rA@UN8!`^MBvb8lmb3)ucGi9p)wmg=_{%?u5g5K;1xgmhB( zBS(lK!OqUkI4?tM>B6-U9_*I4x>?rm_yRj#qmsu054**VujHC+K*Fm)v8g zEZFeLM*fGvg^3skE{946@w+)8C|r@GN0j*5thKH$ugOG$V~fhu(_N<3J7xI-l1hLk zxZrlMDvL5Hgo$~IvsJ_L2CL=yLAAw-E;Hg)$D3x6XNfXfmTh%xk=j<~$ohj`U}JBN z$N7bhhde}z3Ol$3Z-$gEt3PLr5T{1_pBxb~KSqF5Q`|;MM&!gIrGH`{L^!~GXkgBn zbh8ap9doq^R$_ziOn=l4-CG7SeC*bM+x!dI$fo zcPaxP_Laa+D61ny6s9N^GBdjWVrYW4xJ^Y(+)g>#DARhYSx7nzH88O> zfyr!;3;YVZl(hhzVrwAo%oEM$zW4*YJZw5~?U=&)RlhR(kub(pDR<_<^`ZM0)Z5OxZuwY`K;{POUl4I(8SzTiDga&)F6o zG6q?T_(`P5W*V1+O+^~O=hvX);RcrHA6cfr2lN;BBt2V0g$WslRYY*LUO5K($qI}-m00m}91`6_8>9QiV{4u>vb2v)6ZcfL4eFrw8aoK2WD zcK*fT_|0}U7^Xy>ESp_d*t3p+eVqm` z+*gi2O{BpZ2+Y=fH{Pu-fug_CH}&3o;5_%252~4^L*Xl>eCN|nc_v#JHfitI;2E9l zn+!Bn*5mM7y%4qAr{P)-Na`-*{dpjSpmr79C!m|!JkN9E!Mg#KH=qR6{OjiGGgJFz zz=rb&1fb-=_TuE%ARe0ZqmYnV{0ipHGe=LcsJGpx%wl_EqTxt6{a^ob-Ygi6K1x!y zKDCwWtH$69cY`@q5*+35PjFWph4QJes!`_c)$kVETdP34FCaW~4PaW(Ju5r`R7W?hQj^$sW zYooC43JiiC+6)_bCI$4Bl1>x(SvMUu3FVX5!gjDzY*rzww5p{XS#;)knEEnFOk~Ct z-@lk``*YKjV=|7uT9^}3A#ybP=0#F+pb>4bMls0swCSs_W6^#h(SQd*g|l|l73Eo0W6I+k_KOO zvjDta!E!VBS6&rbXoDQ?4j01%_mJ?GW_fT84g7-2<D06zKp`Eq}U!jL+K#XYjJQE|N5z%uE=(r z*3|2XJ`zVb0$^nF}3{D?dP)S(u^j^-SQ^wK1j1D%RB7}ms z@{y=fbKxgvp)Io;fZP{A8H}>=*c#wT}Jy5?A+2{=_id-d$&jF5) z2p}QjoJm6i5iBkjD;uu2=lY~C2LrRx9Nn| z{uy61(1?W|K`!!dWu?1s3YNK5t|H5C1Up$)+?QO2H?A?ddZFrNOYFfHBD1x2ws_qU z>C7QA6WEF|SqJgYuxzif?hg_{t;9%`D5qd*PEe?)l4wb`HNu2r%w49SZ&?dYixcZU z*%@c3(EZl~?equYggGASY`({>FI@ms$-&83C(lO%jJS2sUN0soQGUb8NvqJ zXHe!M*}NYaGOZQ^(Y)yX#$VmmXmJs2YdlI!0*1OV3dJ}mJ!3m)1->}lK>Abix}IB( zhvqd?+M5PYCGpH^Q-4CyeMOenE!s$qeb#U1*A3zQIoO}U>3pB_P!>2E{0bU?!WleiWghPUEk z@GS392A_AXDWIT}VVNtLY7R_JdL3n0I_>|8edtCoQ>na5%R=&qCmfM8dSL|Lo*Zb6OI4$L;m(TgREi_mu1+6?Kbd6Cb zObX4SM(pY`P^{bnYm&@`j5d!&A3^B4zV)~+CEgl2*;ji@0TGY%zNg5wIeA3MunhO_ zfki0s|6v~kYF=MigWNG1kJQ(D0Ln@m*X9=AQCnE}Uj^e)A za+l7gvK55{y4ACyN%h$W)v4CrLE+;rt!~B&oy+%|9JiNL=$NMn$mhjKiCr zUCRiWDt1Agi5Y1HM?2kFI)aR?T?O-%tav1gdA0yKOi{33asD!2jFr*UNzq>IJ`J$K zJuC>ttv8C=M8_fb6!}e?qfiqUCydBJ-W%5nYMtOM2q&t#@4+pAm zV3b!;4&5($ql*fiHIl9%kG^0WT*~pZ8uvS7?$_WJf2;L7pCxTxU9|xGhov|5Sm>V) zr%nSQ9`4#4%fVge83L+HmWs^}2%RNF0=S#O-s>cw9^3|P^B&A-XFBf0dTS`;O4QeT z`0W_Q4|2FrS9@fk%&DU(9hjr6>BfO;i5Rl!J@BUiZcBH$jG6YkqGc8!_WzHTOh9Ka z5CtQ@8iqL7BQHKVU~M6Dw{hbF%wNJ*f3;O~79r2h88(^jiskm)+lbY9L* zQJ&#fHBP79f;^NUk3TjFDJ|8U@f<;GH|L@2^1fybo(841F<>kc^XF>G#A$48*o_wq zt(?aDaLPzR>YwYsI85NgRv}hC_~u(TVqD^(y&rEz)qaI_~G5opN$E+L0>RuKBziW*L1_)Bed(I}ZeQ>NU`_;07q`08)kjX{%yciH)Qt%fu!% zb@Fd_^PX>kuE-)BmOT*&YG}J|dhG2g@Pr;K)0{pw5O2!|hUw`14i@^J*`RxNTs^LL z;|cRC+$uHD`Z(Z8pxH`C5_sleV(Qt4dYg6w~LNhIXtf-RQZ` zQ!Q-3*RK(Hx0XG2y=}VO%mFmgp2fo_|{~Ib5Fd0Q#7v#Z=MLAi!JF^u73b(Lne=b zn4EX5>mtQxugn00qKZ?i%t`g|LmM~^(2CHa*QS`>(|m7JwCBfzLe~qXUfbgZ+{1&d z{&wxvAFZ>!Kg~#6Hz*JJAc~v&@v5v42+YG7gLXJY)Grga1JzU=-KWZ<$#BE%t8ahT zUmuLyqg=MPeP(Qh8jM!qd?S8@o`rsbg}_1e155k_BOoal6 zvsGjW=#jftsa_Xa9l#TGyCcSbCV?0AGprF;Ks=~V>h^rFedw}Wt{QnaRj55#TIjYI zs5etOGqSO?SpKv0?p}NG;lB;4V(+I)os&p#Ba4iwyxy&QA|1*V5u}eOadwG5ylTy zO>=5cjO>5zKKH|=GoasxOdBnzx7EaxNg)^MGxj%BF^8UZIO$^-(P^2O9m+1Aa;hP# zKtxg_xov^}DO(s_VzxVd5{&#oQa-C}fBt2Vz9Glb^e-xL0GTq~^&D2urLV|mPU`?k z-HofLc;h`oHnDvBdrB>~LutJo43nFfNvz=fAysJth}op~OcXV5yS@hb$?566#Ywj| z#0GRFbvB~RwxTHY1?R=d?Bk9)dW78LBF)P1#arFB3B82>o5o#t((eYij%G2X5o3eR9eRRIAqbgTY!X1k{9s+SWS0yNolIv=E69ZBFUK2zGydpb z_4{pI~LB5--=gLpQXtb@tUIHoGoD*FVrBzm%<4%W>h> z28s$oB@7@f>F(f$XT>DLade2KC zPR>+w_= zszP8anN_=4^(*j`<@)jeLIlT>jJEN%&u~t*U9;u-PT%@#r$R3@1tV7stD^8Kf?N|6 zt#Gsp_Gjm4ZQ_ELD(M&Pi37vcRV6&ik+)G=Seoe(I2Jzbf4{p=APyS%EYom3=uC)+ zh-|W?Q@PttRIvpACk{QPvh{~#(&tRmg;?>$qsvi#$6ks?q#ruB{nl2fpIiC(*fJk{ z7up{%ETq0uip`aCQj}W!M4z#HDg*h<(?w9pd~R4Ent5@YLxH-&|BKO&+Q{xrJB5&N zoTXZSD5llA9K#;Z3)e%1HWnx?0I*`s-|Z!7i^f**xXh68&PbKP{m6kEyWze0B`_ng z*^(en?leYG+n?EJ>3lXCou0)PX44F#uuxEO2hIvcdLEz2{%Nhkat>$Z%OHde`)9rf zhBYTjdO`5^g+b(b-b=xMr{;TV`gh9ixtY23j)v>VjmrYxcsG}!8@SNG!g3tlguWgl z^XvUQ#xE(KexVWj#KhdftPc&;l9_Z|sf;Wx$|OfYv-7bt=lI*s5aGj^1>~gr`^87m zC&Jy#`6Noxm5bvtCr94&x3ZNDd&e1CP06y6FdZ2l*hFhgjT22nyN? z94Q2tUM}FP$hZ-c7kJW$H)=oIhcQfsM#7gO3qMYb-6n_w+tk6dsbrbiY#&jrvhLbJ7PVLdQZ5o(V=8 z&-n=F2xF5{bDqxNnv;kdppN^+S~AbBS>6A^N3J8=a`4rShhu_H*N@~paM`6$#|D0Z zA2v4)h9W7SUXR@35@AcMUOTkpbcMUVT?G``rt+*ekz%A3xNNBheWyZ?MOL4l8diVZ z==`>Vs!p5Ygs6 zKH+>iS=0DZrXwrjNU4)P#e=LQvrS#nu;(Ik>Nt|D^IVBko3e2JA!1&eOQ3w+ntaXb zzI**9L|50U>DlKAHu6E{!s8QV=lwfWy<|Y>FNkai*O}#2eng2;N ze4tr@)CO0Ha$wgO%5_teIM4O}w<{dd@|V)6H* zMtXjqFtN&~*vqMmH!JOWx48&NOu>B?D?b#@Pd9}+k(Fd_ly7~Qiga!rHDW3p@=7_v zJwH$=vr!Ah_ZRt6ti(fw1^P9og1(AMXXkd$BsxvF@D;d>QGG1%xafR+7D4mD4tB4s zZ&dT&j;GhzN9B2*3U(uZTfIST&6<=+kfM_?mzpZY`>DKWk&F`!F@DVylXH;ZMOWJ=|h@)pfMG(quQ~CXqu= zWpqAoo*R4SzlB!T-Td5eqc|qKy2FwX2#;weXsU~~zf>R->93t{)x2?&Q5r08V!w`j zQ}CnvV_1xQin@sJcYWb!34~7%HC%|06@~e#)uNzSNx@8erVHuf(M(_3v1J*by#g+x zHJ$aLL&Y9B*8h&R=#{iqQzVpcb&mVA99jcv|84q?Ba{duzP*@s7Q@)b0%qxJLcPNi zIUVUT^Q$nz7}Q9b4Gu10Sb3I{0jvsC4txE+v|#3QL6s0n|CsZ^oK@dslb!ER z@F}`-8P5bZP-1ULqzCD@U9pzBk%6Jb(C`7?Jt$%eD&^|Te0&HJB-V2?tgI1C465+r zRza#DYTTKSno}Gi9XJKhPWx2jcu|M&En-k=!`-UB@(H`3>IpmY-;>Wr7D^-;@~Y=yjf*lc|Rw?j~it*PSTM!+8CYdnSc!Nk)_J-w5X-eMVbY=*70|#lwkzn5#}XQ7 z&v^Vc^wjXmgy__iXx0s?Ik{Th;-M8#dixY1o=A$7b}Rzo@QOn)LQpKZ6%djQ7apxf zj+6uct#dOpf2&;`cA)jsE|3%#jT)oLTikx)AUw6ucq!x;y-S|Xo}?T}HrU)`mhl~K zO<|w&pEAwyt2u63EMYV0Ahv`3g?bkZ%$sykXjcQ+66=2V;1sM}ImbUUD$v>zOyn;X z`J=O<`;D5F;Ge486cz^5P%(?0S-+S&a~V;k^c1qUh$AZ^lV8$XUG5c^I1kztz82P@ zZNka?HuyAi>jtnX;lQ{VpztBjd;c(1@OE(BDnUQs-Q1CRJMb-67cW;At=5#-Ea&1n z|FrxNh#2>Rk-;v*+-6js3{L$tNE{Fk$@ErZFQ_9YEn-`W?(rH*fPX_x!UC0AZi1t% z`_M<38@^o4dxFe432BQfsZIOD!X|+3#fWEOjm`Bf&r{SuWyIm2M+u{@Oy0y>-12ES zm14|{JVi2K(8UTWpgon~vYoqu#GR9|CoRNDl^}E6vRr+jd{xbUqH^I0_b)V9VHe&k zJ7KYEIZOE>v{7+n2*eE8I8MeVt)NpM96~~*bw4T>G*8}js#!*#LNBXKECQT;?mBz? zxP7asH(7d1z$KFYkOcIb3-lR_RLk?V=}FTj3Y4ky)oH_GXItzqZrC9*`?4JF%Q%f{ zLA%_@>qYZ(LHq z-$H?KPGxfbMO?scX(@#`v@BoWkT^uTOu`3O&5<~Z77{#~-K=R|*>0E-^+jEqH)D7s zxw2W_+Zte4PR13AOXo*(RMuvUUEPS$IQJ$Z7>V?@^eYzrX-Dm5us=y+a=SVCE!{^> zdrmoJ9w)dkf(WCSMP|CTl{&sl-2ZAj#GJwybbd4o7AQL`(ySY{&rOXLO`SHe(O^x3 z5cIbDhW$nTv;0En>5UFpIJt0NUptlVtWTZu(szmwGtE0eXqAuJ{(7cHcaCt8l zB4Mj5RK*{-gQI*k>08lAG+XFbE`P>_lTVM&dwHJm{rOolH~ziCdUxx>O~)q}c7c8H zJPvL(s>L7qvfPGwPb`6LQ_1V#yP0fiLPEmJ?Ch)`Zw@lmnk>E1e`{W?WdJ%qKRp$r zOcE(j4m5{em#0L71Jae1mRO%|#->>bETmULF!=>U6dw}~-^}l09Jv}4vT3lnOG^%< zsI`!Ba`A)?ztvmX+Ey-|cY#RsqeMm(W9B5`XhMwY=VA?!8^o5=4{8F!UMp!DMj{o1 zQ*p_Mj5gb|5{4$y$s~rt4c5o+q)MZimIBcamZi6H{0>8}mN+nogMrqWWtx@a2uxkG zM)X*0spc{W-3UN-9W7kV;yJeU=U~I}Yf6%B&FL?j#T<{1JI;ojUlQnco$OwOTr;{D zsN&f!1HXtt?IQ^^S%w6Wl@(Dg?T91JbL;C14|UmXE`PycG~BxqxICKPU`p%#nemp^q-uqZ|13p*fe)3^SRRY#>77n3Y$R~ zRcnSEdrKFqDr+q5dtZ^K68{`uD*o&a6M7f)I}{s>RP=yDw_~ulcfmQqw-7na-!K`5 z0Y9PFz;bL{B!m$~Q}Tr?CwFu_iVh#GN1u@_L;maenzLEss&=8tSj>CT?W7ukxJ#XN z6XfOl_ZG18pNh>0_)_Ct>^kk*8GK`U8}2QN*Q1%$Tz9THUJ)zY-cU3*7~eUm?^3i;0O|uItX<5O(@> zM_iN3zgI2Mwv>JL`gaE)Z4jK1fvfMi+3dCbx)raG#c5(;A-SRweKVAlCUtkmc78+X znUjX~o`o%y-LN3Td)CNLkxVsmLXAV}y+%_;DnY3jx#vxxt!l9@LM7WQtzw+A$t}^E z#2#s`cmWV%m&c+_{O6^rIJOjTE%Ak-xhti_@5uRQ5|4DSoR<3j#I5c;4L}JKm_Mc%cjNdRMy7N4>U|#_>^9m^9lZumRj4s^tN5_!+pntJbNRa- zr;Z|;86`BC-}xics9=3#7Y7vwlY|oR(|QeaM-6W)6#S7S{^Yu6VNM~aiOrXqvg z-XdJ_V|UaHx*H%OB8I-A(9_fBYgUSIAwI=+B*+#U<4~riHq5#cLPA0UaLn*m)adAF zW<*FaF)`{C+0oDe+gW5u1En(22Aj?{(!oH!JP zNjJN&5Msv}?bicl03wCAB2DOzc zaMtw9Zdj`!j9i1ssws2um|tEwwab-&k0_)DZmGrIbi2p@lK-;nHh_b~Js>AJ^1CLTT9Z8i`wod}`(ySi^@_nqXOHyx%?~Pk@Dey7W_~izf>uf=cZ=1ebkTbVejd|~gz>_2qVPs$+NgCUEIjtS(>w{lB?S~RK z069HfMdRS&4gkM|$kz@fj*u_hjhAqoor^0XG7@gXYY<7A9DU{XiHQGo!xaYyr*ChM zl+$r5W`e1=t6sEUgg50EF$&Sp!2$WlN8CC~Z(X1ikv9~;W;if31a;B2??KOS=ma$B zm{?hTx(s;iEU19b?tlb9j&;tS_nb>(KR*J;t$MO-69d|`t4pB|mWEaOkA>~ca5GxC z^%h9cS+{IncX*|<&FHi^f_@%b&|XQFgQyZ^NXI_dRf3`=GY?OsL8phw`^)`Gk3XOM zLLlJD2vL;uxjPJ+8^g0^zyfFN^{P0CwWz#_FjPKP zY`b2jZ|Un~8P`AD3`T%QA^0*EAF!9!`*zsj3(!|C$H9y2Vg7^T#0geWSxq)m`E5lo zsNQA1G<;pxA?8O2Z|;)FVV)_BOA=uGW+$l4!*`7~dyO9+Bw7%7a)R4+EO0sSa1Ju| z@W2uf5b(O{kGL8@VEU4ySfowA7a{b5>d^jdK^+wgkig;%4i1*7(=sa{5Wnr@wB60i z6`aDTbNmp|;NWlfWYUb!33KJL>#P0tu1CP_1a{(v*K5TZ+YXPifKS)U=cIS*)EovD zx##2Fac3`@=~pI)ZLqmgDm2JhxpJw_W{KACm2bNr_Oc5d+t7;yEfQ)Y{N4cvCZPVC z(8Kw9M5oY)b9SQxA^l+BF)XVkHg>(`40@eC-v)2Gl!x;ra}DE-YQPwFkB6MCj4VAi;LlmV zZKjV)R#f~8@KkGd28lmD zZ@nE6jvl%IPR#3OtQ0s(k1Dkw=Q#=N{swyf_q&Cs>G#Kddq-b<42k}kfCo09_0oR5 zW%uoNW&}6}9)G>Kj?>A@7O9@N)|^TAlIjlkVq6aLq;#+BP4BJv~};M2t-kpJ!PQ3eJR6BF=Z zQPgH#Ou1EhENrZQyZ^MN8|&W#emDmhbe_kQe#jOVSmTwHlsLWLgG_Iaro8s3g!*g0 z-P4gTSnE4KAGYnh-2$R~$nuJcUyY5ylmzcFa(({L*sV4|gN(ijFt+VLY~0t!o1CvT zdz}=gUEQ(G7@L?7MHP}JNbmFoLAKp5>#@{3L%e>gCywWTp+*#wB2BQP2Y34+4~+9* z*gDVO=c9k8cS1Gs$W$!dDo{)@H59-&{41o&IQ03;u7*aK{radGD_CH8dAWu?S%Q}Y z0N+KE*!=v-l4wxk_2@k`A$ssoblI)1dbT)@)~>eN=1r)>mu9^~cu4ofd0C@aHOK_V zYun&*5P$2+XL34MwA!MmwG~@UO^us_ErhPN1L)&}=bub{xjk z(hs7_T|tn5^Z0wqk1|L`CS8))ze{q@+t5zX952jf)M8)M+lz8sWq_ctaP{rmtKK9N zfRn#|u2*yu7^Za3iCQkzc&^!2(W=nVCBf z2(A=RTHYs*Z>1>{aftCFQly2oG}24p#6Shq@W_Px-yOGnnP6aGoj+0;uKb}>O+xVr z1b}6KnsN*X+1=fpO;jjd_|l2L1+*l2?E}M{AVUvan`S(hb^;8rXHlYX>%FRa7M#p* zGuB9b!FWhmI+fo4o*Cg$Bb+-tn(QjL-S$BA41&6Woi~~rWQe-hRvE=VE^YRA&G)@mt2|ec}jQwQc z;)4bIeSSW?I~d{oXOYHkvja1p|K^iENDK%RORU>YN<916rzEK=OlJ1u$+D)tIvIan zvcXJ|g$Di(U2wBF6^z~7Fj8EgnFs}^*TRH8+0Wo>xgS_ z*CF8d`V4$cxJiC(Ey}yUKd@hNj|;a}M4ObUjW>CYcZe@K5C9u1Cnx81J&avn*A~dJ zzkl_%v)FB0+l{5A?+i^_jHY^m0fYfSpvBD19Js!9OZ3zeFU}eXM2c^Br9u+r>hRqd z&NZe9>lqaG51YRd96EiS-4l9SI(UAE%W5{Xy6+cRC&zzo=``kD`S zyi}x_*UfUNApL!Nbb!Siu%lN1yRO5>FMP*0UB)yqBcnWJ%1A9D07?2xT6pvRn}mwL zsgc{u;hY;pIzxLrCO5Efv+(HUU1+{DOeGtVEY>;ArWk3JmiO@yaJKyyL0&;&mo4v^ z9R>ylfV-mUYW+;pANoUJum1)-@~Ky9=(|p30f>Iu-pA`D5YI)JXMllCz*{&7yw6vPs3`Jh0C%W+h*=*df9TpI4j9N5$?F9Xe1T%4vKHI>CFrlE0nf8T%04@AhMDT-uCKp-=@4@kcD zTYgMfI^FU){%X;394r|8CJId3D=DE|^t?J`b2~$1)(qZu36s!ZCMcFBNR!uDOyQM9 zMVZm!UbKK}keez&X1JxJU$MHsB~Z+$L3!P0mU=aLMXgaMkZN^Em!po&D$c>^QVk#8 zdT)5F+oJ#xzZaEKZgObPB;Z3P`pCN5!tp?;^B0`UOQ1+w)dPnZSEPpP#@#*rt8-q; z+*f4`Y~Ofy?_Vht?Y$o7tK0!^+`vJZ*}cvCD^;b-5!K!fefRLN1DqRykLSEzz(vt) zI1TDK?}lOT^}JpHSp2_4fSJt|zN6-!qiD{IO-MjpJaq@I`U==3Ah+=P-4A;mm*p_f zj?XEqp+T-@ZO7w?fH>HfPf8$fFQJ@ zV)W;N*VAr<^Ft;_+fMK;zBx1iS@1tR?R(wLja8#j!<=Lkl99qy;jClqPMgD>|$RUL?3 z(=#&%22q4!e7cEppGKC!eP*B&?k9=VF-pm2A6H&RU1OvFz*V0$Twf2|=9Zf8k1f?O z3@@4HvI^rvGbz~8?d+oz%uQ46Z!c1I^7(|_}y0;Nwn(&Ff9_$$5{~t)S%z4q=W_v#3Je* zvKx0hfT}1^$YP&AAulN@t^3>l&h2vtjQ9`l$6o?xNVHg0LNIS6nyDKjHKnGKI)!$n z)sgt0$^7;X`X<8J2?cUz;pdOpABo@p7I0sgo|P45P`!J#i|u?cih6f<7jDkN%pBO> z&f|A2XEab;+k;V27;bx#2WTXxmqbPo1>j`J<1uyLp)J=4z_PKiJ&kMi1m6SJaWsL9 z+w1B}Ny)!Z?X%+kfiN8q1Dc@T`w$v^+@#e5LO#H9?JOJMga@gX54pGB(re_p$VAv% z4&UTP$|XJeQC+;ZT@`vzjw|WEpAThXkHHCXTIUYBYJQblf6`>X1 zX@){PHs!Pg9yYSDnSe8&RxvfeLgKVHBvYls7B}N}w4mK+f#lHpj(qp{xIa#}{oV1~ zYXFde(tCXcM{Us6*8aqGHOtP>rG(J{B-pxB4x_t3s@msnfFVaw_4`uF(UA!(U!M^+ zX;U5@@YSm2?6*O}RJcS$k^s=Su|YsTF|f1q1%TxafxHRmA=RcQNs@^emr`T-WO2&G zz!2sPEP8*x$ZwyzNO|BA;LWTVh=1;RkB*O2sx?^H*+a!igPxzCogR7$se!N#a5{i( z{09&mx|jgEDby@Oa$k6n+th}1N(!$^<)Y3vcKGX--Po&wJ#;P>`F>5rU%u|X&bkZm z3u-K|bH{}|KYMTZKW;j%0!Qd#cvzxJr;*YSCsGRoa2%i53zQTU4XxHa+7v7~v;GAL zW7z~nYtvIJCr@~UaUOFc?%JfH4wjg6C)Wo%how1Tlz4cb!wwID|G5(E92{ZS*UmtU zQ2LJziGa@o(f5HLSpQI9U+|Tr7fO)6YWy^NWMstoY{l8{HtTWVF=(@sSfW7r6T|J_Pb?m?y27Uf!EJS<1H0Y$4>~Gc z37)~r+}__SiS4qh-ny8XK*~HhodCVT$?}Zdp4t6{Tt@pH@P0f1jdl zLh^)fndjrv$$1U=kniZ!HHA(6k{P(JNjP3zy)E50#LyYy=MmrKOGx|Jlz~+!9YkxD zrp!f*+Xv7GL|6d5xSbJ-2cUhx*VRBQM*d%K*Z$A+9>%wGItrzlRw8=2)_KK}+Y!|y za;wSZv?e5x#At3wIbKI2a@{6Ujg!Vg8MEXrQCh21?p94RHD~6s9qXbe@BSQ9X`rlDcLWCj0?< zmyUe_>X2Z#X#ywo3k?5?+;EU_p=wUtm?laKQEdziDca}sLsqtJH#aT{rqPAsNu7&Y zSt356TSqzdk(HHnZNJLRyt8+_bzBkUh^d!R z^3~?_n$3C5I|VxSOijCq!~T~Jf$RBa6nP}#QbtKI!1AOC`3m7SCWn!4l^|0duMw)p zF*6D?@ph=Oi=V=My`ySzM%lF?Boas0bGG1qV=SYeI~OxVXd`vjR1d`tQOvW_2MKA? z4Lj0`IC0zUI-|X=4JM(Rs&OOX_}}>4UT(ZwLkjJo>a&-mM31ExWJ?)yr&8v&y@~Fn zIjQ`FMbUyhH2vPjk6kr`igQFy-@ni+!C}hb>R*>icQ53|orB zUr}e{v3J(Ac?B{)(+1wyxlP7zr_pFIf<~#-Gg7BVS?Q$ZsR&f|Jw4MU;S8grual0O zy7tB#zrbWaqa3vkVW}4DV+5q$KyNMksVP~v;-%{;d3Y_UA;0!YOpzXk=EE403BTUJ zH~BgwBw)YG<)7=r94n_I86V$CX|ZIeH1NVYfcj5o>!|tM0N< ztWBsBRpIs#gFPlDY#|TY4-u*)uYVV!02sBeJdugRY7%f(eIQDO3|`M;rDLA z?99wvuZPV)6_d^$tT$bbI58e5wTR(Lq*C+c$!pjT!Gz7A`Mn&8*l9gr(iaV`YckYg zfT$qAK3Fa+?0ES2)AvzHMZ@@jf0dfcbDj0+r`4eE-^|b7E7eA);uRp@O|8kgkGkI9 zO0@`AQ#kD4a9Zv87_1K8m00EG=KAqt#1WC(R@V@(VWPnjGB2x;`1h2(3$}O5@nGWS z>%1$TY3?M&Wz$DasqpF^#A9!I=5qr;NcjT33v5xUcXYjn!ygmRLb9RO{q6Ue%nl$m z)z#INL^(&UgaADwLv^OU!*r%^t&=#x9xejY;h!sUFHHh~2v0WUl+0#*Ue9@RfY?V3P^rf#2G+G3{S6qn z%|eEu ze3iVCFaKQ1an^_7uYmyqe9}+_+M>q|XZ_GQc6`BnHhBrZ3jWcpe*+)^O40zOKHNHP z`hG;~FI&Ft!dKWq=LY5(%0FyCQ?%ab(|4M0fq=d~^7Hm@PrkyGgHL2haPshYge;xh zJ_>eEvM7XaVL=?6?pitVyG>wZ0LG1SDW(eL2b_zk>}W~vz1+ahu=7Ehs{a4|;kV^xmpNndt;B2ugp)nauEN$Y@n3*27196z literal 0 HcmV?d00001 diff --git a/resources/profiles/Flashforge/Flashforge Creator 5_cover.png b/resources/profiles/Flashforge/Flashforge Creator 5_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..c6264272b760ee2ad134612e67f18faccacb9321 GIT binary patch literal 91283 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

      cbC( zPfC-EO{8LP2{im2K88u)b|WGqg7oY`Tin05%&Sdn|&jr$9bUy()zS69RCD^>er>H(IF2cZo;j5 zUo^kQ@%Lq7!#4%D_A)d_FZ)DVGJWihj+=_cWb?2N#1EcwuIppY*1Q3o=jmy^S-*!} zS3M#1?~mvRm(uKnR;Q!rLPJK8cuGMH%2C%jEWtin?%cOoVwOf8p4Nwo;VneW4eA_qoNODWplhMn)Nk;;A{vve%?U9?wsaPl&x#f$f>tE@ zT{?U9_cH9)1(vy)@BI+G{Rer`oVl{^KT|4!m?L<8-on^-=LYP;nm>}?e(Fq%2Y{NOy!>nA#MCo(#RcuD zVIH3eFXuk%516H`{k7x$b8{Ss4{ zVIdyet04U#S3*44fJ4Ze3)mwV*7mj_q=^f|eXa8ur?7`gj)JfCP5T+ls72Th%V(0b zx62hsZ{53}6MSGLByuX{T2l~APL{%wP0k2CmxQIFV2+s>r?w`$g%{;R4zs}Z(63J7 zJm25-SRrQgrzVFV(`G$PI^kdhLCX2R;tM(?LI%zY*~_xAf4NM?l};blfK(4|&H3Y%Ea>3i{4ok) zV~|f)dE)6w4N?o_Z~)F;EmvpJfDwr88@~JAGBZkJ>I!PtFGqGR#2kf>$&rS23WUWK z_u?>9IeZwDM%Mp!Sg+ps!g$nFwB>Y6mdQaw#G0uBsFNJ&-l79b?7 z9nub>AYYyYfY%@P`_(paBch~WdVrwLi$VBAfcH+1u<&}mw23}Z&3!wE%Uyc0S44%^ z*o1%Ftirm|gU6#$e+auHgj|~SWMJHart00@3E`~db^Utz1XAkSncmN)sSd;DQ`BJm zay?$s3nmxPVwBiFavC6x6ef!Wts`^5>lwU8I*T{echkab=M=@9XVvTsH$bB7aULKHEQt5E;wM5Ye$d zai^phC?+#3A~!)0A>{}9<)R;_ZvQUZQoN5A?lVdF^SZO032&fk-5fIPZ{(6n2>JYh z!Vu+D4=8pAe9c#|0xgAWJ}$RIqNwPoRNAXB9ir(a>r%IrT-*{ytm*NOob3e5)EdzS z!`OJ^w@b+|`kaiDf^}Tj#X!WV%5GsWwz?vBSThNAS%9mfJ`nD?_1deaS;T1|AkQq`CxiU@`0!hrhjQo$7#3LeK1X%#{faWFz+tIriE?l zICVf=m~IanT#e0Su&m(56&ap)L=a2^TT%@}4Z61dKR=GX>otZT5jC(=KyLq|{ImN{ zp6l0-2A(gI_)XjX7H+u@LZC;{4|j`skQ6ZaqfJd6{#cb>WG?bhBERjK}v! z2}bsN(z#T}{!ECsiwUMDB>J!ChS;TMCoF)^=_?@0aGaC0ZKD$?V}eDO<;Fc2YxCMX zQ*&j~xbA4s;PY&8-xe0vIMA?>QrVk)SxHpC>XD=p6Awk&pF(8Vj}bmT9^6HlW^1*c z`XgOw*4E1y7?6GqiX<9$lb|Kg$?4$)-(e2;8x%B$&3uH`gI>V<3~fd>A}S;)^c)2}?@W96}f}J<=+G8^naHvvjU@+Ukq@ zqBCXH5-!eUm;lkx3qVyuUK=k-vlplIRJa|a71H$CD_Zh9pq0l>IdIN-os!HpA0;4j zM-?OW{H?iSwnwGnlYU*+dPh5@{=`_!muUp;KORZ$LBy4$~zcCuDg5_ug7gp;u6?m{NJH#0SDNd zpWr8okqCwJ5TvZ2IRtfX`{GVGA~*-+qz$;&FsNk7e;D@37v~mrKmbm*9UUMsNyaDg zrd=T#ud8IoJzTfv6yd4QsL#=Uv(d(4(U9u#8nLWit>7bWV`BppFLq>xgZjhso^Qb= z!II%K2*4C_7`MwC_xp`f?iz8#Wr@YIAR>*Uu821Axs z1}yth0H_~w}~r9Ki%+TyVhK)y}cPxke)vVmmZI9fdYgL z00sbIWk{{y3EV|s8ni+n&P6;65I#{lO6lP(xkZIUDFs4I2_^#7J>EVwlQf0C zA4yj&u@ySp>qiVWMe<%3?vd)_IoiyM=jIz3?`7Yfx8Gau<&^>V1rR_az)T=66%3Yl zYJ9bPb#Xzmf`W6zxE#LPtYIa#j%g}cCj-GHHghVO-*gMa6r^stwFM3QVb9o7~P|gt8-i~;6G2CbmMZj zS>sNO%TenxpAnPQ;a{+J-(w2jtmOy0x9Q2x@y8JLSPi4Ykl3LD!^%G&`+s)+p+q!|LfTsU7zlzLxwdJ)wXq7WuCBD z)83C+0tJFkJr(>5C#Iph30L*Q#a^E>nkl5Fq)5612AYWmYf?px%XG-hsp_@7G{jECYv-v%t3QpU8)geky#!=Fy=}V3TNLtI72l9g zER4K~{^hcpXVIz4fr)>kqnW47kT8Ble+4_6x61B+GDFrb<8S02Jzi$$Q6JNd>eAn@ zNFRtAcWZd*_Mq{9$cU&0`b!Q&E<{C9ATe7=0`upG?-_3eY&?-Y1fOu*pi`bl&pq2+ zT*I{G-EU+V!9{D?wgH->?}L|B>U;1W4P9RRe6ig<&2wo{4EqxShNpDpGRx+Km~j-D zm~|?wc4&CqJw3+&IJ;N$8PCEZkO>~yyN!M(cx}y2T|?to?tl_kV+3h%;Mh0>N&W<6 zr9z^Nn-b4>R3d&>K@`i82WHCabdIN!6W4CnihPZc(B!1_uRy$Bkfe5~A^d<#%bs;; zPtm<#v0L5YRE#y1&h(autwD`44K)^)g%XXL>mFYQ&v$?x;A3F)$J{HCeq@6R`|PrV z%=(u`+Hnsk_NMo4n|N;1CHGg?TQJ%D6k8b>P3yFCD&D`kw}m-)-8bYwpD3xi5pOI1 z1;qk|Dt6J7|0-N#?(PZxYxm4v&IX=ra4d*@SH$e}IF+0dcm5RyoXO)-Zza`?zE(Y6 z>YaYCMoPHs*a3s{RTF)HRm_@Ym;6-a+H1;IgFHoY*B-3-iAEV^J;vF@;eJ1CM23~J zMQ=-*9IsOHlHI`dq6F39IpKnl%~2|H@-eXE3dS|Q4jaqmL-;Kb-T6vZP-7N$pfEnO z5&>`l?iuZb*9P4iRESshe0}2c)CVtL>VS$(Kht z&+XSG{m}aVOnRh;-tZGZQ4s}tb|iX;%ZGz9L5D%smkK!2OS{MZMndlvp%D20ngRq& z`t!B;TYG!^-Jq=CZ+;)3oghk1rtMsPxm3tRJN&N~)92~ei9ByU;c@yVouqRWo#Wg2aW+KO|HGg=J7Lh7A z$T8oph1V4kyNHp{YBjW1l;5_KYo6B0!ICYgPAMYtEV83sNg~2xV$J>gQwDLtY_$>5 zQS{9TRMH;^qNw#57zo@A8Ikc`dC2`vn?DK8^p}Qg9?o3NqI*z&LA7pzFnfYRLasWG z1ua?H(*mmu3w<|9$9uHj5Uv#P3c9qsCEO@G=jX=3IIYEnRq~4|04eyq_r%%Uu3|>h zF_O6k+c=dS91&REmv&j7E0pdY)g+jc5`)h3X@^zPbBw@^L%>?||4PP&B64;x`0j9+ zNlvmrppqr>Z-MtJ4X+LnI4Y^KS!pb0k~P~`JESh-^FR2hHuI5!LM!}9iOu^pU$*I( zkX1VOoR)b4gAviyRJ=|P1rwqiG)sbEqLZ0FjI;`RveKWCoSb}g=2mn1Y}`XY-hFjY z{Osxvx;(F8i5ig46N4wBrwHwD3sBuZnx?-UN&Jngmti|+)YJ3+df_M*y%ltEa`X@8 zbPmu5%7BUjE-fd^z%S3{xI8FCG_J>UX;1=2`T0Bx`W zD=*FYPJC87+=gM$HSD%Pbj;57#Yxb`)(mKU;LJB`+w0d0&7+`-R)O{Zx8qsAq|GcO z0=%bSj8cAl7o8$N4Y^Cez}@90x~!yKsCyswIYQs-nflxS5stfBw+xJ!*7*$n3yT_O zT8LX>iTQb|7+}n+aQ&NJWQgyZNfTp%SVFaXuaOd$_Hkfw@&ms3>PeSC`jln&Z-;3T z?0i^gSo*lMCW`N>HBkfkgveYoh_dJK>FE<+e2&l5TsO1Ne+F|IzG(&h8YWjvJS6#klyhA=AXFW22$Sg9b9p%f%JU4<)<~cSUcH zdjw=1yPS==AejPi>gPWc(Yk&aTn6rNbCF%ZI%xa_QX@%f^^tWo+l}jU_%ZbApJX06 z3UtKO+SVNF!MKE7ZBZ492R} zyz*v!-gGwA)B( z@x>H4KH>mAIccDzT--7!w|1Jp#r$tjQK|m3T*}Sg?hsoDxB~)LM3B-WB9}gEEuT4> zYdBAy@T`Ho`XC8{;XQ0FkqJy4ZMX!Tpup&tu6q3=R)M}g9zkp_;mgnS?{lX7kSq)$ z1Y9j@lX511zBjcSH{!?)B9!laVxG35C8FaV1uQWOBG2~rs&~KhfD>5`OhcL5>Ay`Q z7BxKntUOwAlSI-W%`Bg_3=9k)6xY6QgJJQwSI`1w*2LNGc&&y#XfwqF4tPK{!`yIj z7PK=A3_j$aASV>qk3gTecbK*x4zL9Di^v~?IL?|ZBW7HOfmS6k$m$5ym#7wjy)|=Zql+9bJZjHWHw4_Rm!nhG7y@m1Cvo>|lx0Mnc-Egk>+*Chl}SK&tJ!0;W))^V zAnq`D4Qb+DBmO*4G{Kd37_fWadxd@=bQGOvO)Inl)cHrirTIi=<(L^diBHz6RDb5o z^}Fzl{JyGLWiv~rZLfjTB31Z_FZ$fwmHEKz_A*I9pXY_)nG57dN7} z=y<&IFiUqJWc&|w&;a{reg7!NK_9yaaPge%mJgXJ=%aE>i-D%)b}OYdW&Q~F;wF-g z3VDL`pbGUx|6BIbtyZP}O;nNkOIoD~+qM+%`!}NSRaPmNQYFrIO)5p3rN{mVz7H!dn7KFi+b z5F0DHn&g(&Vwz6OgN$NT&d}jsABe5o09tL~+KrN*bD>EnYIR{d;m@(EqLh*BDQ$Ii zvQ1qk8>L{%zQT$j*YNanet-$Lwpz*-15m?=TPt(6LHZH*yEi>cKmYN{-`)8UII*9~<%Vo#yXkylTbd$f$c#QMyY8KpU9_qiC4Qu!KL1KTIP7wNeBT%<~hIOtp8 zMeV?0Q~`Jx`e_CUZ}J44UIAY7Kxh7V)$3T@;$6&46~-iQ7N?e0=*>@*_f5Gflpq77 z<=#)3t3AWxmh7UggG6dZlpl=F=7gI<#Zj-H26=LY7p;LfEzycgNzXPEVi=u>5tj8n zx8C;FMPQbDP8O%axCg-354j&*zw8Rs+^GHjwZ_$Z`50m;Tqa@a5_5dUFWddd;7}lt zb9;CABua8Y@vRg~F%wONi?+RS&%u3bccSXiM~1aZEc)&z07L^NE(w-(+S~3Ln-Hh< zZZ{7@%$+oB?v2brxY$ZLjf1KxdEyveh5d>}qI|e5JOs`)&rFu6`Ufi{_TrrR2`>4P zOEzT5zoJ&I4SMut-7zIqAR>W86!7-t*)2fUq12y!U#$k_ysK@aqoeLHaQM1mqctu$ z@A}?ig!qu@7`AIPRJ1r6OyO`;zO1h$3E_h`gwntpvxbO@+Mw9(>W0IA88rX_KgJMoC%&wo;8jQpQgqisFnb4$L5ftJtR zwc)$QfAs>@DGrH(i0lpHv`dM#9hlE&#W}ab$@|qNZv~9!^1DxK|5*G-lIigc@=TmZ zua}&WM4CphUDL`d#MX$B;+F%fu)xiY` zN-?1XC3gf>pVP3chX|;sg|EgtdF9!cIBxgi-<{xd+E#RxWsj*#P#W34O_w%2tYuSO zL=5lUcm$)f^u1lfeq)5`E_JfTf`GnkB@wS zd4|ScGa;R~ORqggCR^2=UdJ}?ABoK$YY>axC@Mhw@ye9J7X`!c2gLBeD#>@# zvq7DkUGUsIr_9a8!6+?o~e~SE~KD;%|do9YTW*&*#qhp;!{O-uZWUngE8u@q?IO~LYbdP6~9`$sr91kP8HUh%MZv? zqGvl)y-=BE<3vAqi)rS?jAKCk!u?(O_e;|MYCdUOn~RlZL_+kk6HsqZwqnG@x^WbeO|r$| zcx7Vc# zG#oZZE+aZwfVY7Ndiv901!J!ElJJ`2Bbo&x@1(0Pu0-_smby|*>T!Z}xz=rEc#trw z!Kt)`SrR#;NhcZV7%+%hIB3bJ9+xhrA#2u|pz_5}&;jEv6g)_}0i^yY%*xzSlbuRt z?zuepA_Z$u!#s^wUz5QsB({wh8&(O^e+W4aFJ3-|Et^A1JEOH*5^jBk!%BnZZ<3EU zSoQnb$LP0phW{Yh5!YruN}s8)Qx)B7sjG)CW=c+WPs6IIV@HMR&vCZ_d^&Oxl-?3H zGZ^&DaJw6Ny6G=OL>)P9n7!csXOPOC9W{f=wg*iTWDD1+5nPj%5B>Q#8=Yycq3TWL z_r_e{mUaofS$2erkxZs=&41Z&L~?^F>5rlm*R>VzZWuy2K2d`2<@?(mPio`BtQ7ec+zyO98C)56*8MsI z7>BT*qaD_6&yHSfUJ(@W`%fLF-BWvhg93}3nt>+MjjMLfa?K$pf>HEa7)8}ESoU*a z>ng5UmN|JxD!MHQXE%iLYS}uSAKa)(CCH(WWQb1rqeg1L2ItW zqK_~A@L#*H$RSKqwL#NE5d(TfTy_j0 zk0tjXuM!dizm(9z8)RP&?7o$s*}xclsI@+_Ffr%EBo|&bu3H{VBA+O@CoA8CJ=M6B zPQ^-?`&OCOqLF{bpFP?ZR(AZ|#f{eBl_u%w7CZry@sn=?^tcSfDTjPmpq+W2Rjj9| z`t(iutZ{H2f3${q4^`A5vOyKQc4gZ_CPG;9-tT1S|0*)UvI)gE3ZzS$<%F;F)>X!G z#s$;RUvK54WR;bOa=oKbpyz>&`T4Vh`$eB-{>!5G$SLWjZvQJX#7s@az^3%d{$0wv zme*0E`>hvFTxS2G5PyQzwX{B_a_bqFEe?fjyO#53)a~qPWEp3dC__Tj_k?%#{)c1> zQ~FJ~pmv4 zHN5vKcQ<7(Z!S<_WJ5)At(I_1-Y1$d>uQ?|jr+in+<@qrAa0IX*k@D3Hxt64OZ|pb z#!4piXi1%%%leJVWnZ%d92EmDo5&Z(oTYovWCkR==U(Img}!|rp(oMk@G!EFDBv2ECuXJfHbWZ0bHixMDj1&tvf z0f5)!|NH1m&B1!Jka=(LW=w^LJT(Ens7*Gpn#=!V>8#_bUb-$$gEZ2e(k%@Fhn5x; z=}zfJx@BQ4viTTa!*?X<;+UP|IP`3HD(fv4L zd-6cXm#GTQJV;eRI=}C%FY2b18O8uV&fe!xYu=QMx0OfKxWGUFL;T*HZoq(KZ+=b^ z6jLLrBBh?eJ3o9e-M(d**VSfZ|E99(fDfJS(Dzc--tCP^F^m`({lt82id_-R1PO96 zwfc(O%U^SOwf8r~(IMbA0PRF!ksA|seGE4NVxa0p>M$qmWcQA!p7X@E*OKG=kENB2 zr{H*|fi^5lwVmeJ&x$M+6#bhxGkYZx-*KwCvnr07%804`1wg`zV%5ENJ{8#O{qsI$ z?Lv1*!8?Z;xZoW=nATA z`J*1aq^6({GwIz?+k0cC>V}jK{tB{5!Y(jaXW)i7+ySQ*<6Cuoq;`ZAZKi^xj+%qy z3=JKsGWN8u99Fo9=D~Spvo$KE)e<7^-=0^1C=k#rLj{8o;K==(`L@fM4q?T7h2z}= z!N%c*G`ghfrtg8fzr%0^1B=+oldI9I#zf9gHh>f-FN@RCCYE^YnS|1UY4nE#HQ$_cXi^$r2dbw zXX<$GBhs^*CdNadI6mS`oImfns9-7q8WH4T9-H)yFCM$r5D1Sixm`ec^W$DaCUOcO zCYyqutY7vY58i%#k9~i*g1}#VjT1~4s?%KL_~z@1Ow_`TgqZWHv}CaQjGH4f+c`F+ z%Oc28SvLi_BXU!qyva;^PB9?&jK9~E2P}earVIax3AGogSBXX`t;$?Ns)j@jn(Qj- z0x@>=dkrm0`Q%{`S`l@KGhQh3yTNkGhtAPx=C39;_}!`t^xCeASbg$DV_oi_rRo zmw285W(Ed&p>0*i!%>Qwr}2MafDClAx8ZiX7q`yCR{ka1Ngf|XI*$C{rM!!zc<;p_ z?Y~SL?}zO7vj&4V07(M$C%9#(YuW8%?Ry{3bYn=ymtt+=)C_WyT+XMc&8xLZ1p%iG zw4lIaFXXfW*VEgZ0F<0tIUjWcpsx@Dy+f+(0?)%(z2-HluxDCIWuTI&_3x&0g4ziA zSizK*o#@Ta=>n(?ClPQg0S8`<{a=@Q%}vW~;@o1wt|NajmO<8TcQd-JXX5OgvYUVY zCuqQ>qeXq)XL9pjW|YkD<%TjPWH=+mBXT+k4>PTiTx zxHcxY?3~vx-^D$9gM>r|uU{o@_JlRY*XG_Vyx>k5YpI9g6^qMGfDQ`k(|&Cv>TEm| zsV0{?Fqj5%3qR7APCr(PO2)PJ-Y}Kw2nh5c-Ex1yu83qdjfZ*aDU=mARStWfZ`0Wl z8wc^5SV@LG6^X_@i2Q1O^wtk}xKQ%qR0;uJF_1|CBv{ol?3%Ed8m=N{C@#<>gUJBs zMFH^ap?Rjqw(teM?|53(WdP|MyB)1rn2J)AU1{i~bgT+NwE-n=>Eb~F5&Da_tDSK zp3-Eel5i7KC_s%Eub>aCpod&rdjov}RQG4pPuIP5%b zBW2hXimN(5*+J`dUa1@Y;gv}@6{5UhBJTNd8HdqPb|3bq(1HaE!enz#_qtVQ`(@-< zE@s)7C8{Nyy_Z9PrCp&RBNYlnH|&EQeSK&Zv-|yG)n#o1gjdnwsw`n6!E7(~y4)%O z-ZMFwHIB5YQFaQabE=&n4`1;!eAz%NsYpa9HyF0`O--9+F z!-QFemSw14od4{n>^l0MYhy!agKAHn4CO2w7`S{F9Pke&ys{;h29wyW65lm1+6-k{$L+|mps5a zpK`!t%Vyo^Uw_q%277BzNv}NQv;wN`FYy)F6jL6Jp-Y@QcPBj2zoO>m)kEHygYOh3 z+X6jiy6n;HU8t}PO_~-kSAr~ncq=p|`HfO96BcV;ETaq?71`P=Sc4H45@a`oG-|sG zq123V!r|@y*t)R=K?~|hy}O0?b4h*m3DBuv^XcnVoPbE+6(LT`Gua+>Gk+ioNb&F z-2UbDAv*D*0D?scV8nNOIKRr*R7_AVEb(rBG-oHe!>WnNO|;QpDynzsc&;MG{#%vy z-_`oqH8UciZiY5QB(tOwVfb7q6~_=l`vDBxfke2W?51OT2M2w+pd}uH8Mm=+-+^Ft zGn2-ho1HEG6_W4~c4C93G~@D{5Ctu{9tey5y*Or55@&~A*;_Yc&>#3k?Lqf0wUq*m zix1!XEiIbrvpbmbD6+$Sktl#DyN2j5JqGl5h|6%uki(BNRvE&EGU@4yme&R^F%jWx zpiRWC4^5X;M3SJEra3UQ*@Y<*(4>;7I)Ycth1VfAFX&j#=2172Pxl&2DGG9Ooai9) z!TdMA&RW*J&Kb!U6(=;uX!_U<)-~^2&i~cYbl*vk_Wm>7!eT|BO)Rr`tp5F7`>-VL z><0lsGD?zw!~>lC_wBwG+ccChOJRNgOf*AvVq|a9)j?h>f;=49y4e$J!pY>=QaR~0 zCBlE zl*x0fa&?|R=z5RXq@LZ5%VxWMT0%%nzF8KNIcO&5FqqivK5Ex}c&@Lm26@f>2IZxw z&yhnwQ%0yY9G}gy#hCl6F{IH;yeCwfTVCo0DcBm3X_v1U6#1FwkOOuh)U zvfDLBI^5f%qZg571)?8AL$eQ$edkLDy`(HZZr9i=nK=aaM5vm{eCE#iSD6ZRVG}aY zMsErw=98E@!w_~HGf zsA3iqkfI~>Ij4z(^pZ3{p}W7->;rhc%*s&ASWBEc%A`}WWTUdkrdsg3u5n{_9;pLt zc?CP%DGP3phsM!={bzTP5WWW+UCog9NeQY&C$O*uzn45pz;_b(cllvaLSLUV1?ZG? zr#yG_D|mA7A)W)$@Bd+N2!>*M=oUL&WGq;0^Y}QSOQJScKk(UPo&f_9YzPlNBN(fw zUhHHLfP_*CF|Xt5%1YPwrTX>HlP#(fT*j)3CB0}#XFYie8T(?3a6wZlp4p39B-@`c z1aN#uSe10nQUvD`Hh!=%%OEFdz^Y>Tcq*7Zd$Pz?1K=aTmDNi6fc8+FRMj|j+;=KzZB?(@ zIalq5PeT-=wnvhlVYaGj-yur0x@Z+?<@aYf+n$e}xZ|jk8J}&=*2K}rL;e6uP)lV$ z!*LGtBu%1dHbO5AM&KJtE!wD+D?#mjm{|2cthv z00NH+K3F0)Ngf+v4yiuapVOB*rz$Phe7C_8m-&T@1-k`wF>BFy3A~sUhdhEL^%1qX z=Wf^!VgAjB+xdwFyKXT1R9_!+cmyiXE0Bx92OlX_8$qMeM9yn9FA_&jiQj=>OZYGK z23biDsfy!~_=}3r%5dlG7p#S*uXK)5gV|>jP;%-YEJqYX9X@nKx!?r6; zHd*fpzUAcXc^gZX{R<7~pa}&dmEu;+Z9DOlf=WQj=yjgEcX(I~x;shpLA>{wOsh(|qB*qb3?3(G!~?=}dtV4)16FStU??b({bGoTdxi*#w@|ccjibnZR|t zlg~Z;acb!9W-dS8pFVN(q6Xiqwzz<|HeGpUixAa$=ri&*s|*h4f6~bOInX9SIoKfY zyf=p={Hj>~al|TvJVdde262vC?{Fq#h?#mEDIutsA=5cd`!>>3W3fk~4Ogbzc~pcM z@~@L2J>~rER|!6k=V{7d@}P+4^2K6HJ;2Bu3c|>WR5oPiT(!~{BsLM zgd;Q5wBR7ns>hTiY=#533}*8`o`N>4kR4mzr~0~I*UjSt&W5k!L0|*{9qOOYFZHTF z=p>2a9`a)R8M+bZKIn)VVwS;B+>fI1g3_JYhT%CeeMwFQ8_(=-S3uN2_@+Lm#_0L$ zs4<6cMvTf_mpA}*BQd%|T*4+=8Bg8pe_#HJC`qd_qd~;Y5UI>EY4+fcdsEC0zoU3> zhvWBbN35ANoDm9WTI;PpSoyW4-@6IOMQ-K)d(yeRiglB@SQCF+j2A-?b4cJvxg4`P zKh^Ofhjr&uL#LSCAqsb0%n*d8m~+wYnMh-Z^L?|H?!WROv|VXs@w!|lKpVF`dOk8l zrWG?8y&1WXBT9FD2Xnf>>H8k4=%)vXm~Wj`kCYb- zHyw$Q;gG|a^Rk!TD6*^|B&M7+A=7O2rphhFX)MfqOt zFK@s%_N})rRmpw?V3`6Ohe^UARj`Ie2%=fLpW`S;3Z!bL_=NUWoy=PXJdEsvA87yn z?$_~hQ?y@SO})^owWlPx9Uhu;oSqlmo)&XcnO?P-E|dGJ}0x80b^EXd3&8da0JIE|=_=55@^ zW>G>al~Rs??$g!osn8OIKW3OB%xwRHnYX51wWYPFnCs?+EQOzE`zz$a+$*J(LL)AO zcCt!^eaOe{%sBc-?7`3A+5-EcOuHHV=cL1P-d3rGF`B1&A2+Nw;Ub52ZGZeEgHW7mG;%l!R8)da%FdzRtN1HLQx zfp<|!u~@uF$o(}{!c7!Ve_vuR zDQ?mgpIKJXylni^G8sr{aXx=utQH zPhU@%S*c=?)9JsmNi>g{=M2KxBph3sC|eWFFhcW_cXBzQ^g~+|tBgu{K$~KBKccBc zaxM3A!%!5{?a+QUs@jx$@+&{m0zKO7i$Wmb?J=$j=u3?v^ze1Jdu* zBhg86&-Ds~447hfG&{HS(9oR-=P?G};GoywKkR?d|96U$BF$eu-z^MgyP56tC?_J)4TZ-W;J z@1vkNzyDLR*f~)p`EB@2D$#$quSmkjJx6;Q4gYZ0*Xqt{Q*ZQ(F=K}xFx_^FE~+t# zr55g_WF6F6jVXcS&4jyHdy@@=l??B%gw5_hQaLzu*#(ynY}74^l%HKTro(3?$XDwInS9f({xF$03Q%&AFZKHN-6HlH z;NbOZ`Bl^=#$+q&&~(y%usdnhP)9evsVtL)J!ohx`JeEP?p<_x_j|fHYx>i9?+B9` z0N|?6-1Yj8$`kpWr$jXW-V|iITetw8&$8vm^gv{{X5H~dYlyxB+=j~yLFU7n(+@O* zX?N>}pvD$|)TnhI0QAV&foL&NYBfit)*~nV!2XV5{XM_NiC|}6oxDA>3>4EF2)Z|z z#3+^`IM6zaj;4K`(_X^S{OsNcLs$zx1o<&C^L0|q&5`MGl(pr0En<`IIB(*scbYtPFh$GpEKuUEx|JuQK|3FMZ;K^LeD78(X zR>(2#HE9!{(i?jTybNS;YNU>osOIC__eV5&*wL9L>XsKv{~GavKGC7Q6)HQahr`d3=w^je3>?&Jn?ngp4AWY(kSBY=f&_>x@4` zvn4$DhJ`R;;4hi@5cFP-15dv<2$-()>M4rNDbg6@wWi&$sy`4~(#1-3hbzHrqDGd{ zL##{^C|Q9km`HthCPu!a~A~*m+Q^<;?Zi4i}IiQ|4SJ74?;;eNiM67tNw%bCn3Z= z$Fw&$5&B-!@k`0Ve^h_3P;~PbEav-4c=%ndBODbGm4^Dk6~(h zW_w;pVAO+tec45$r;`r$Ay@~=ol$Pd6csZ{{j1H&qV?ee!nAvWs!!U@dxu-*maF0U za*qSu33kHndD|SC92%-({NSiWIMrH7;Y-yDFXh+jHr6 zQkD)@vXnAF`4Rbo`CV90O3zK)p!`fWrxPV=ad_&(<)}Zw@MQpHZQ{J;oH8ni`Q`K%N=9ErWwq<6yfm6Jywfb{j=7LBjO@#v9>$xq7xFf$k zj}o0q^l+Q+K|gvSEJ4zNC0cMi725unH-TokzqzqEXgJE=uUxzy(=ElGM#jwN$1zAA zVZ{JNdp6!no4^%edV;+8CI5Lf&B)BJ@gAsuTe#&GFd_AwAa=CS=jiEKU0Whx=({bp zRcx4DFJ)$T8hHBR*-n>+IC$+?!l!DYzd}lRu5KMUTdDoE@?@9%5x4%H`^ScqT9Gvv z#LvW?J?J^sU*yuuV;f|QZauUNym!K2eHy@Js6w%)M;Ym-+b7I}2}zKF{fhlLt=vz9 zOi@Smv@|pxuIA~x-+K*_y@}d2rkD~B?SjXX=}*)>TCrfzA{2M9wZnEU&bJsy%2fB1 zBGI0;mDP2rR2D)snrCPTH&Ix0!>XQ01+UD zRxNbbxs16spw)$)7mBZ^KjGAdb(7e z>;<1rhG?vGJrL%7TJmYUgX2ZmL^Lp;A4Hc!s-EAe8$N1g`BXVk_0|KfHsI2%ZqK&X z#O{KXLDNPkj_#}lu7G>(*-Ttm=cq*B2NNPo-mQ!5EH(t@cx9Y4KRh%}YK}v$%a7CU z1)DyyYt8VmDZS~3G!i7U`5L~4cT;jqtz<@PZ%`C{Y+Z=7_!zqj3QKh=Q7nf7+4?Kr z3B^KKV!WPvlt$4vQg_WvDJ2YH=Nq2*?lvP36^~w7fdW57VF_Xecb1K6pRc^vj0#?# zz;{xhZLhB6SX$dcC_HD4r^1-5e7KMs9`soUAUga~ zU_e*GP{fO7S``t%mI#nw?Y8OqBJ8E>c+`yFl*}ntkErq|Md!eLmd6ygWQHhYi1+)y zJVDT7u-?lM^Qyr4^Jn&{``eo6&0;>9BFow*f-gImEtmE2tA~!hgupZq?m#j;`-kB6 zc@<=L!rjSh`hl6a(3r6z*0YINd@*(E=AuIXoCeE?!Qpas{!RT(GyK0v3iz#cs+s&V z+3EbtgB+WUU5b)AxG`fmsXIN7?kQR>Cb>)j1{r*YiQHy$gLgs@aLmRq8BhKYYTEOU zv2VuwbWZc(6)y8u1A#Jxs9*5AanewA4;xBFfA-9!??yk31%x&&@-ls4YsGKd^jPt; z94Eae&lZXgX$hlQf=~GW}Serwj7BhqEVQw)gSve98r>Y*msI6Kvf!Bqx~6 z?vkr=m+KAKfh)!8H+%T4gC(w}IT?1!+l=7G?+wVk-H9`#Dx22 zg+iVRUrdR+_URL~fIG;4FAcNm$wCRtb7Cchr>l8RI?QrB2+QBr@C;+n-9Q5CMcM63 z(>E#*-mQs*Ed>Lm3qe|8d(A-`^SOhFu{u)8_WMN8cb%u6w#eYV23j=s!@7&3SR z;5LE$KK)!#b@a}d&L8ic|K6agbBxd=4>$uq#>MGogu6fews2lamv|eW^N?p^+$ z%`EEg;4(UR0&gZDlobAtkhd7n$QNgCybs1H3ia;1i=1h`Un^^S#MEW}8Sue?eS~l4 z?6+gG0fJlxgXmI`x_*M0DH0Lit(%fG7{1srXp;J#K%ekE10Fm;)=JOdWc+u2NUr=C zjeDbR`}ivylS$GP+Ej9fp+6qGxqCQ1!&CvTbA5VYm<@>pmw6yv^6a>i#v10Di?oLkN zksDR(P__(2(^4>F7*RgpZS_>wSDE=nL+?a*0A3f&X_1gy!U%mor~U~ZvZuRVcSA1` zPCbt5`KB#iLniU~IDJyhwG=w}v$rXaCu)c=8MovbvjCg%QY;kgecp6~_Ra&(r)>bEmh}eDpm^pnNg03VJ#%$0#_|mAx z^o9RDmr<{T|2-lJ1%)JQYPfXf_T~i3IlKNYVRpGKA@~L0OGM6CNlqqMu#zh6L8YS0 zS_iK}oW7l$SijKKGNOFRyAfzKQp<#YO_+xa&Z!7y=d;1C1AyYl^fj|1ca~`7ICSM* z6wk-4)VT4q7RR*^3X+q+M1*4cQZe zQF6~*1rs7ww@r*wF?T{F!Gn{j7Oy!6Iuxl3KA<~5Ni;(z{TXhIwG?_ROs_f?k?`@~ zs=ZvV+sKv(3TlTpCrxEz&ahTTr%w)i$Fbgbh^o$|0t5~#DoHN854%I2ROaC+Hv_4Y z@k~zQ`C%4~Ro8#V4--NA6*gRqG-pri2u9F1x4g~~b5E^VUWiyR-`g(Rqf6|kO(bs{ z&c4TOIlGuI_wV#3Da4+3mgM9A&YZ!Zj{Y(s*x;wB@0B#kk`wLP4!rgx9h&gR{~YEI zG&2R%5>T}K|JEK55YwM^Bf>#!;j*OuSsqt3-+b$$`1}5-=ZcaDlm71DX5%m86Fzbw z00=%^X4aYw&rNcxbdp!8UXwC2qva6DiNO~cc6YVNb2pqwF;p@&D%<%y3TKy1Rai*Q zr7;ghbdUE93{}t=%<_N`Yzvno+TSb0Iz?Y?mNE0(7Gsf)gtBbz%ys4rre*2ALRb^K zhqG_F4;$7!N(?K>3e!gQSKsEF_@lb>lpmQ)M7@kGIK|3(b@JvgZOY*tM#UfGgi`j> zuc%xUp|QQqGNBP*sdShJPeqR3?bLdtC9x_hM6R zh1}?YZmPrptCM@>N01CHdJcglJN&MYP{S5v0v*czoK$@mVZ#1A5&sMi*+Wuw!36$y z9vyBHJYv=8S|K2wsBz}u7TCP`Kr|fzD4vyFg9zGF)1|vk8NkBR`VKHTEGdB2LxcLrUXxRjALlDjw;6QjxmZ^M>Bc z|F6;uWA`eB3SgQtCBNR}u(1i|Dy?qDm)|ejqsdY*v76KdFMrg=B>uR}Ba|dhm!KXJ zF2w*L-}F?ZRNnVP^JtFrVntP)We;Eq{<9J6U36x?{Z=^~6(evxzSwuO8Ih2H_|0)b zL8i#N&*vjkC(GTJ3Vi}hUo;G+F#?qeUS6MWJ>s;u>{)#t-TFNImrfL#9*h9z73A_- zdlDU6?93LkY%V6Q%ViEuI#W&MfJ_OKIr)UQ)??)_}!e?)vdBYQ*tQz%@e)${l?PHh}VnBUq$wM^idax)s9h2@PoCgPC z>{n#TD)dqb-c`B5Yjo&3pUJ8HSfMMkjy3k`a2OKYks&>w(7kgfx+}&vV7PRr`QhwN zKmj*SL$RB_V0B<&&OiZOfkGPuIFNdT#%E2|e)6s1+cP7%HWLI1&=>waxZsc{P!_!A z{qHc8`D3x7VkY)1dh@LNzaPi;gCg$vU)OJ~8?YC-o#wZmNH;zp*W0Orr$LCL{WjZ% z6HVm=%i5s|GZu&nE=c0;8#>JFOIuFXn0pR-*Iu?omXvp1 zB0{ntQ%Z@eCDI7k|47dBXD{M>Seei1v?a*MNIJkj&hLy8hdq~ANK|WLztcpTbLJ)T zOM%&(6)O!nWOo9?e@d~}yK64uaS#^`mRc`}$qk;l&pxv#2Mw0yJV@sGepy&kWy;(WWiX@y`#V1B-XEq^bEDPEDIkO zhDSo%-}dBb zg{${xTy4My2+zK>(G?1pko2)t?3XPu_ znG)S~XFZyXao=(WBM*PP8(;sX(Lo*q{Hu|=)#y<5(|oA_zzqV<&x^fj0OBqMUOxD- z{a=fIbEPhsYgWMvuKSJFi-|gS=IyorYc)u3UJAsG*zYf=ieq>4W^y9S7<>@V(UzJuv9B}ufUcK-mBT3 zmYPx#fs?`9Mz1|I3%&}e{ZlV~FP2U=aqYUw&AkgFH#4>OIZSN&SuRsr^%T<1$y?c= zaJlAD+AA9VU0a4}&O3;1m7|7Q&UW?k%vH z0#%BDva0HhUlX*q=3vZ2XN&?@dEZ3*;hKb^%nGq4&-UpwBGGWMghSE6`MQ-uU{SE=%EBvs8pqoYQ_(dJFk32TnVj z241|c6cwp^lUe2;A2F**mX5dYbbd-OX+!&j}tDjg3j91chZ^2gM z+aQM2=&Q;Ho`G>IiS%YH`P=>2m}dc+jRnJ2c*OS%@`EF2pk} zCuxAZL0D`lY+lUzRb#F`7y(t01*nleZe>QeiNpe)bWs7apEmI>!4NA(20n+wnqzru zG*C{gxfA@80)~}@MBV&dydIcofgGTw9_o!7l#xM4fOF$}l`AsxGr;Estmb-`7bD_Z z6w0F`!MJU*#}OUKp|gY^Bj0SBJQ!s#$W3(V98)=tyf3zG{+DsY6d<_#$->f$=d3U=u1#E9<}fcXfy{EhrGLP&rh$r5HiFLbnUmY~WAPBckMrt9^F9DVlKZ}ra! zCB>q6KoC{{m_CY`qsZEtdP zQjbUD>6k#N#bk`2Y>D-M$dBT)8IgM)9PwX zO}JA2Y|36_QTD+IEb;e%Gz)&dw)1noFa74r)?53JjL)B`zZd`QF^^5t#f|$XsU{hh zBiMLdXzipkRQ7SfYcF28aUEGn3Ju72`BWl&(vWrWf{8Tw?|xfA3J-_V1=m~d4jrp# zkId5wYm-8@lZOBJJ7gk1asRf;=r;%BfyP66>YF~IPHqpxHkfxd?v5=3W+vp;j$_&L zf+RBbU9Pv|H4A9^OeN~@n@T5aU5+Ru-zGXp(mmz=@DlC~}Q`)g#=hZ4Mhd`*YQ zHVl4j4l^h;x$0(GY(+g8!S3=;U<~)y|ElR&R;i#jTL*Ay~S7id6KnF^{H{0-`}0 zBr{uqmE-Z9QL*y96>3ZzED*4ZXGCdEMryOGbrYl)17)q^#F;ZU|#*OnRwl-3(ajjs`qZ37$38jn$225b{l5u zioPKF>B3 zFB;jjN`2}<#0irISwU6qu=j^5)yQ8D)-tx%S#bK-%luMeu|x!+CqlLz=4Tx#Fwp=0_wQ4Bw5j1Yz?0;MxW6FN|E75WUpmYH1(W3ry55=^6#+)$` zQmq??8E!(8a;E<_*`hz>HOqf~h8Z{pO@D^(%VNxV?^ z#<3Sy&IoB!3!|cOdl*QVL*{c|;%2maw%eCSd$4UDhL z|KyeUJ&Ng1+ke>5pI@LnnYVp`UF+O*x%R@Yb(2o5&xVTJkcV(!Zz(Hqy+?0ZQ)+BX zLvMbIL!Fn6=#Il-v@8|x=l*Pkhns=CczOq*Asz28EF3Q^Pym<%V92u%1{YShh|*zp zf^-=eHt-+T$bJg}F6sCxYBBnSem8&u%H_YWHYCT^pZ-DtK{T$;$S<^U((e^~-I(N3ctfKU z>uD+W@dWo50O$g+5c%=9iB?A{79a7;sfU}p$wHQV8=cS3Uag7FG-+BtEC~@mrbeX3 zedI{Q`*>H6kS2#PZ!-T9^15)gqK2{;QmS=E4{pui{eTDkzTSGx_4xMlGk}?ACg2tq zj{_Vpnv_wq4=z6rn%xbq5tKfE(r-dZtyZPL?>Y%we$N<6h>i>(gv3v$Tu&}nZEb;y zdeJmV!wkVIq6CQ@A5}nlvU!?ttNsF`b*9&SAtRcD9=JsF_1$YNc&+>R;^&)?fKrY6 zeg*ZU4G||Wm6Y`3`=9T$FT4k6W*&VK ze-mI-Jh*qhhG>E9XZ0?&cO8t0u^gH&w3@bFQKbT2O+erfV1#C6^@uK=U^m?iJN85o zvfWE&1E#Rw-DPT8;Y|o7zOvU@rZxY{DAe76Bpe>fw<;t+(QBW6_?0>kQ`*tmT(@%q zGai?GJ~A1D^n@GV{p=o2E-DmPT}9)2zKMn)CVt#{&4LeO*Y9GU8(Uj+L4pPcQ1v^= z2<^qbm2ebM!3eeHMhohcy}X;26rYN zY2;Rh3SP_ul%O^L-ixZV2-0UC$qFUo?5`SjKr60J+1J|84JIGaUch0z#B{nz@mX7&brx28C2n{uEv{>xIKLNKaBK)ZxLwS+81^rg>S3t0T!;mU^t#X)D=%m9z?<5}%W>*F-JAFn4x zFEt#%$Ad>6V0RCj&QxLX9fdX>HTGb4H7&RP5F03nS7Eyb>XUzJTd%`<13=z;K39VU%CtDjux{$nGSfCYl8SXQ9fJTrkJ2?dGd;t!BX2KY<#MA0Bdu$>$8?N1Bq z*eZd9Z!jpfH|2&4>5VV;MFaA*dpRJZ^SOa*H+Z8i^_ZR9_f~yN|09e5<|z0yr#DUV zyKx~>xp1A_fY2lvxmmkPIo~KBYE41wlVQ%G-FQ9<0cE}ray=48Yu8vT}`i*AXMXdfj>J{PfO)K0A1UJa3ygJ2YbGJIY%vc+~P9vez7P-rYs6R z5#<bww}21zR_IDr0-HCvQ>oBM%i&kG=1^yb^Vl7Jfn2-dAC9eQqTld-c?9 z1e%9vAo}?1qte`<`JeC8927!MaA0+56oUoU!5yQ``Zaij5Pua#COhdFEk`iI{0KKD z=p4``D1&U2IcnV5>K+hO|2sfpb89nU*kV;A>s_ukYX_g%_vsIPmM_0g?m5|^mU~fz zmv!=~#Ke{+5j>6k*W#tybG3 zs8A%!&3dty?b3%WfyW6BE=&qfP5gqvZm;mvlBaRLj?X6 zt4wzy^e_ZI6={)7xdIKKK+@LMZi9}BVf2=lyL2nURx@}RApnj5@2R}J(&-5i2MCbu zmTO{_8b7>vGxz%tV0OK%W|}AFOCf8bXxG9kP26p$jHgGxfI*SoW}L3G1QmkBd^nmV zZ2ME6(-u&U0&b&5{Vyv8#UHQN0{|SF2}aC)I{EtE@EP3o3aUgTz|J9q2u$D(2F>YG zM_~2SFO!7w>0hO{elmL4eeZQSYtXk<8EdT8_R_ps_h6<4?%tDISqS^*E|Wv&@=yQb z`P1vFtoSZW73NNDON=D=4q-?B?%1e{p)pVQ8V!d9Km`V=C*B*i^#eaZufH}L=c zVfhyRNro2yVgVzn&%#xqNYhCljFQEke_~LE23qJD#`z*D>k%$eVwR3?8zPGy`KFU` zLT~X;gp{E&rMj}>+49YXoggz393yMx->hz|k>uZaIbd}D?KYqlO!i`P^-f0ls)$?*xJo6hv*?HEGz;E`a`LM^qIJ0+u2G9$(Jcmiyfa42=?#nXBHrn)>O9dGa8JItp%+nNRl; zmnGB-g7y_mQvyN6r#X6?N6oA7GR5YA%DF#&C*ePMX+duPb7p{~UOVw(PL1x3={CJS zi4Tam0tczr#ZM!Hn=U5tcCFj_Ph{M`Ot^#1Lk&6KgLG4ezh}Zj!=w4ytguZKhKwg< z*AobS_p=9J&{k>>3aap|=XhJ~H;Kz8_agZfCY>pg>Mng<tJnTXFG%4csj*v%abpd8D-xEe zcF=W;wU?k;Snjf+sI07NyaiS3tYOE*#$4IH7SdOAe*CyaD=ZixPwhhiu3Zo@s$P(i z1PYg|xq5tZ0Xu*$>H?=5g|Ih4Ls>2`fC55D1U6;(UIQ%8=(6?vd5Je=s&bDH;|4DZ z>MKD^=5BE8Ww2K6SE-T_B(;wfGowF=mQY7>GK=?>EM`zr@b%0QEzg52J+Ed%N0R4g zq?DB1%lE^}D}ai{2&lhlWi;?59CBkS8m%aB-B2}&kc5O)B3q(HuKTB)8TiMnN>)BzHk{piPF|Cqs^6G8xQuB$d@~Ve$nUmVRe+=FB?-DF9{5Vv+V^dca4SreR3N-iD{b%uN-r4JU}?Ftv!v`sEfk>hzdi0;V%SVptxG5$M+G{= z!6sye&II!if0}rW@<{JRDX^JxrpStH*jzw1ho=DXmK++Bubt7|E*&9e(#6dq{3^^> z00?`X&$r*O6GSO6tT|B-?@g5jmHBLXL(d!j0?59>#IAb=*th`;9^AC|ctl@?_<=Ex zFK0w7AnW!ehH6(wVP?yu>6xM+UhZ3w~EuVtI>Aq_E`OCL4SZD01?r z9WgSMQNVFFhCU*G($uxw1-4E zoo@>6d>#m6z$*wU+H?LUF*TYOFEjtMNjtFY*L27 z!)3^KhhkH|<{2Og+57txO^7eMnllcEW|ADVS^s=(ILo8|MT*^grPb(mnL#5^JAZz- zYkl%LqkdeaW=}?b{uc`HWZpul%E2ls12uk=KMlhG+b{$bCwYeAS>~<5Hxy2K7k@jv zF!ul-#Sn9fFf`B=m!bWD2UN`wM5wYlpJVJAa}KaNkpdSUt|WeU@WmD%`EH3`=EsYB zkAh%~n!Sd@X_rlvfTra3^wQ}vgJ{J9(1eeyzG1vk6 zxjkBO5Gb1I3CX}$UaeByFi>Z&f~P7R1(m$e5_R$e7TF1-9vFFm;ROII{-z|yPsE2? zN$-FbLxjqrQ*TJ?%GNo4O@8jT$h8?hvwg1kQZ4Q3muMVTX@a5Uya0F#?FNI#(a=lY zvMsfgg)0_BnbW}o4Fd+%n?ULDPO83FOc4iuO|L!^5^^Y{-P|Y0{!+l zN-KCck3(NFOZITrQDJfbH)nfa)&;gV(AI~eC7~jdGRY0}65Ett@R>zzZ`V_nCU|Xd zDgKg|sQT^rdsT(IP&QN1rb{d&!UB^mNnNCdpdk4BQ_#9z0`71gF|nBb{{F8|X916+ z#F(ATAVM>jU%fP>gx3U!&Y(b04>k~yajiDCBD$r0^JH3=RZi&vlrfVPmg!4x8N&mCOwW4 z1{Jdz$T0_*X57H4zu-KjqOS; z8G~<*;nfCLHP3!jldZ*mclB5d2?+rnWah5}0FKAgd8`yuVGpb-79XcT?+oN8Qn#wJ zeg&>Uu(A}x5ZpSgY1y>olA77}z4zSXbDq(HMjN*ZVCzO9bJR2e9@N9rfuBzmrEKca zFIbqM(4G4d_#r|gY!#nw-UCl<1cSo`M{fwHe)gvN} zjX(D$-(B3b{QA)n{G<4{GDf&bT{LB^B65Ng$&Vj&UsWMjqHIUe1<&1DmkFm748H$B z@8qsybRr5(@+veE!Cc$~xbw+Z%~w&5bGovLG#|^D(IrddzZ?7(mJa_RDqFxj;s8Ru zu-?5p0bqL&e2ef&CXZD=&B2H1=7qcRTymjJqzoMxMfJT`f%=*n8?V&<_yNpo7CKsV z<8gpl>rNaUmeypQ2IK^Qojx`-rR6zC#)7DJY*j?9ptIwS;on**PEUdvfJjQ0(gF$!0xI1d(jPjdyCnvYkPazP zkQNY7X{Cgr1O-G|T0pvE0O`1UzW4qOcb@ryhnjikJ?HGb*IIk87rzILZ%ECn zP2K!MTjo*8@HQleoz>&jY(|lc7U@kUCS%0uT5*)>@E?8dv{~8t0$c^f$8RU}T@9%? zVr4l#_2W{x^Yi(m5^SbM!gL*Rt?by-3S6+mq`3@unINmUT$ixNfce^6TU&Th?EoP1 zpEX)l8T5vffswLq+3j8_W?os^PvDXMQ2Xdjtdk=<;a@y@mkc}NT64q4obLihs1B^j zbeP{Y7EM0q#?39dO_tckOZ0a6<%W^bTh!SF4CREkIxJJ}TkbA&11wznSMqeavz`a+ zm4EuQ9oho*qpmI)ag-K^P|3&cum9d}ullSIn8cD?hCE}l|LR;Hx7y`+>fY6@_|@?i z^9(fq3KtCSMQ6D_tDe%=Jj-*S;BBO{To#`aCk*LO>E|ED;@R<43vPXBldhPs_-Z?f zZKutgG^hnGcH+XPS~wT^%T+QP01yx+Nb(5_Pn?|1UP+8jO>Gdo!7$IDVk3_c(TLeR zA~$4Q6|vZOMWmQhMYxU7la3h;V>_V6cG|OA`HCp=rsYab2|)IB`RMp0jp%?EIX(;> zrfEJXxO0K^Y$HV3GkzZ^w{^x)tZ9pJ)uO3 zvV{u;4`|=Jb|V`XvVMKKZ9^V;M}%E%l%IXeuxwOJbv?P9-46G~ykoz!Scfv9Y1Ero zqE@dlkaqF7N##!H2`!YT;@yywVmrxWm=^lCL0|Y}Z~pn+>qQp74X~oWhq*l6{7q`g zD6h4yl;Y#AT}E_t_Nu|7clqV+&rzzx=o1<4R`nZWH5v*Awk@n`FH1*a%V|E>zxq=E z#DM#VuD-60?sql8=|%1?@LU(L&AKz;)3oCw!Z0K7UxSI4A)A-(eGsi1< zzejPhZJVxlf95i%zL#FYzef`>=%=kyQ_ijX#*w|&G*_`G7xhy$Y{YS5N7lF~y70w0 zt|sKtgqR6Q=#laql;*FA=6rN>_Gxl>Wz!7hj*+z;_sPw6RH|{_N6v)4Fxs+kkQW`kZ4_J(;Vh;?mW|^UM_biUxs`Fp@W0?Z z&3fA>;pMV=jWk=bb{o$XKHzj25m@T6pV(d}H+ly2*pL&S>TpMEYirw+LUIgEyPA7% zRCEP9=PCLSSVSkiPCLk>wW=31b!_{iQLr0u%C1+2Rq3-^)yx`ce;SulY0;33fl3L? z;OjhKUUiRbo@TF!gqn#$RrL1ucGm0;Q_qs8M9WiOnjcl+>M3HpRz`)m;<^2HFj{zg zeB1zR)MOPEqnw^p=y1ugkp0RQ^+g~M;{$wZd1~*xnhiYPw~;r|*sG-;y)1ur$VfDa z)yis-qu0aA%M%?gZsunjO>ACBX*Nw-5SR8QWHiH%Ix1aEw?C?az}}ewg^ew8rFyCt z5D;K|H)V^Pa_`S$EG10J-*wlGLY7@r-cJ!cI7fwR8@;=8*Y)()g;_v=C}Y58RX@~F z5!tn->4uwjQ@lTMvYyS`MLHdxeby5=tW!$b8){zTLrx~kZAg*(6NZkw>k^;85y3Ft z#Aa7fb}t_0e$M}5udAzDn7!PZy>x{s;o{=r>Wo<%EIdpGviTauXz{wVAFBYu@r&r(UKN`29t)#?PIne0;tQBgsH6DEEzfl(cS^R|j>u%Az@z2)kxWtRK~&fwTs zl=UM+RuiE(wd~>J=sopBl7opYFQoIdADOtRAaae(C@jt1R7u87t8!U==mow31(zsB zTr~@|^GY!;?@EUT-N|!mLTauLhJGsZ|2|4^d@68&V*mVnMKTvgjDbH+F+-fZ7FTM$ z1HaXeIE4ZjPo!r0td~D`67qEzCXebE&d$z;*ajvC*REYl6NBmD1tofAq4H-H*Vl1? z{@`OdkQB(^w`r!s`7b$X-o~||fiRiM|5$EX@l)OWihUU24ZW=;-cq8v-0 z*@}0{aW^-%XA;pwwiKVWB|kH*pzyo9H*Yi$o>0nH@u`Vs^(=+vX+}@c7~X#MhqXgI z;LsWHQhPpvsoLo>_fMa`mFi?soWH|*YuM9f6l$PCIpsO&_%tQ0?@&Z}r zKM>sT$5k63h)4mMY-(aqN#$z$7D1Q`hH7ABMlZB`8{>GqQ{pf}bi3Zl>+14CDCis! z|24H7SAaozHJF}Hc9o0PVcE=q3?@dM?5`|#L%~5zeq3})8bCM2A*zLBZpg4l43$a_27+B+*f?9Y-_lgCfX)Mg0Zf# zaf*uD*=`$)AcVlGs$e5*dq*rUid)n;QH(Ry-cdQf<~II?Db6GpPV`C>o`G7n-Hgrb zvmj39{g0_j;jBgkeu?LI!$tsra0TPIR#0d0^6@Qh3%e~QKM9A4T#$WPbicX-2q4!Ky^@uWXIF6l#bB}8d*gq!oO=5T6$Bpq&ueIozy zo}^~W_m?nXtH7D*h@4=Rm)&^xjXmS50b@!&3v!~jsUOz9s~(8vJ5`*R9G?7QwrzZd zkjT}0tSQuQ$A$g-FB!z+LHpmPC`RHaQ*D-tES9&roewdf_J*Op2_@wX>oki>qmac; z)jo6@bEpT_=}*CI|NP99?p2uO*qo}{fwAbhWuHFDx3p6@ z21+n}n{(Ht$eGybeZ{;*5;|&Bvg|POxwHVFI8r?GzAWL+(Q?zX?|prJS2b{oiUxzx zV4%d!8;;d0LZ2%WM#q(NxOzOrQNm}t-NfOimkW220!ElBBzLjBV|;1Y^6EGY@@;p% zSl}Vq+=rAM=0XlTbW@0J`;^)1oK~>y=5?t?vcu>Z7>HWV_j({NxhBlu2)9GXXVakf z>q2jcy@rOw2^)9wv1N5#UE?y8?g{4LSAKlbADjR#=CI&&6G(P8L+IIg%lA2SukX=xk;6IxK)B1goUHV1I~tOd^*A;DbDHMznxQ zaNz6K`UTMJ#TNHK&WJxUG7U5xI?VdbG)1Sx3LL#D~5S$dha!?(w zQrjoypMu@3+_2@aQ|dtG3AdMl2+!ulRe5+hN1w^zz(7(!&>7Ni-=sgZ$YGR>;zDA} zF)fL+``SitBB>xsQz`uVo+u>&dNeY)27iiH7v7*ZURG7>xVf3(X?T#Z@$mZsUS);tGhW{uu*#2^a7<_LL=ZB|uO>KuompAJ1j}sVs0sJ7dIl_-=+l#&DqLjP#I+0<5o@vQ zA$^1aPZx!XYq|O)Yy}u9L>yk*3CvQLej+@)RpE%7zLoz7wVp#NqWmg85#hv{)&mRh zCJ+S6ec5pd2?-g)3vyT_A+#IBQ^n)6*0<>|RJAD2=V@A67ZN35ID33;tpFJHRM*r< zkNulJKCXYl!+eKu2Dt2J_DMy+4>Z~l9vmGt#y#QhU9n%SH2L^LIJ&4=-H#MMEZ_a$ zXvy&FYUQg{V-h$eNlTSq2IAB!auV=AnGr>L8LaTvWd9ERkH1W`*zq19;rxp4hC*cv z|C0v90&Ow~Fc7^E7$ps&P$)|dN`K>j(l8%q*!mu77PsSdxdScu#>0nY+n=*lE{=H| z7&_8AA@m~syL)wdc1U$FNQ&n>@G+#^+$u7++esu}LP+Oo0T0LN@7W>4z7#QXy%X5A zF0Ay#z@dIE{zN97GyMv`@bU%*tyo_8gU1XBIGjoTh6!v&|M%TbBr+(;71<;^ycM&W zbz*BO`4nsYD57eREbHjSl7Z*p8EUvVDB7}0NqHwhpI6=kSr-U{4|5Jrp4Wr%bWoAQ zWHuoU_qib#^)nK!6IrQDu{B|p9AzDA7HhQ+&KH#)pNk9yOtt*;#XkQn+~AiQM(uA4 z3Y7F^nJGGbGxMH*W9Q>a`%Z0par4FLUYzRe!E>*`=Ir|MBZS}n$#X~|;Q4Kh?adQ-u4uH2!v!<(qI9l$8;s zAMg<~j&EdqUAt~-O=|Dv)(Jk06@KTaPW>#u<@C6z$;oDmn?F__^bib8{X{O?E1zUA zIMWgR^75mNuo`<%IX8jXG*LbKL;|tjjdc4?V1;xbYLL(pU(2MvVVIUDRVKxp!C5Rl zDP6ELvT98BUkQznQ$MraMwm-KOP+3ZUr2eeZFBsG#Hy0NqN1Xx-`X0tFj8}ZFHc+% zmNUgMDd%^wUbq;(74_v_{*`{Mofj%QQ#YSl)7hOS>Qg_puc+pGrim<=3XYp)gvzTA zfKj{F@mi6D{J_CltSmdy9>Z#7YPId%sKYPSm4wcP5f^bBIES3{;=Y6`AIfp`yd!o#H4CKGSMoBhmt? zXw$m$U6PueJwAS)n&vS#0S%T{F7LNKuYDob&g%TPwCIq25a5iMF?pQX9NmRjB7Kwg zu3?_>g;Xn5XpFCje{qb;V(o%r4k;4)9f+dz#`kZLyg6tbc`O}u2K@PML*j_wFJqr=NLqJaCq(JloOe}Q=hauP&nUrl`UcR$BH z!=oj`7sp8U>+J4U_BBoy{ctZKKz|-vR#z9O6G6s7OL|>hkOOW|3lHu;JC`@Xu&|qv zxo74NdH=hG57}pIC9{5h)V-Z?dy4Ck0+08p2a?@4V@%Bm$HsY`pCkA7*CXv}i)-w) zg#Fe~KieZImf{1KktM$woSw|*ABB`)+`r+sr&qEcj#LPxCCu*)a4}{>#b8tH<=%C` z8q)6$^r_-JGhM9*@^gJZ&w#`H7e~ABdz&INi2QI>kSBq&b8j9GKh|3c3)%S0#jxij zldqp{UHS0QGSD(Gpt)E`NPK;Lwf}LU`p~7IjP6JlU|elvFQhQQd!*yx^$^<6$IsVkkcnZ~|< z0nm8RZX53Ok$}tO@5<-oJM^$=nYnsm$)C}Bklez<{u5zyAT@krZa3%4vOrF)UN0d= zvp`=4yL`u%{4chb99%ou3be0RCFq!3PK)> z(qp^f+x_<1)%w|A*i?#*GkLCC7e^Z;)s)CR6@9Qcl4y_=5zx`0-j(HC_V|Wu_mU^5 zRwlH&l7;*riiT=Ze#ctZrynl)v?iH+xPF~HQh;Xf+b)huj=~QW?e|}+CVgvux!&sL zHx3#+Gs_^=aI#WPNJuQh6>+WbT5|)-u5M}xjkb2Dkm8*fychcHEG{{(%M3A-^!pUH zVofb(SLycl)K(JBP<@VXoavE5Yhr^-bNE8YM+0+f{&W9C%_j4o`$yPq#B<{Y^q!@% zUF8R{Irg)Bu5+34Mru=asG5%5fdg_;-$6Q>PcPZ4?=oh7U#aS@#HqLs2I==sa<4CP zt&WxlZvF%RurhJ7aVzTOWbiZD&5T%N?gT`(&+$G=SBb3&FNck z`S+iRj)s{`8QYF8$zqzLN2Oe+44Xw9j>O@lU!tU&3W>zQCx4!{(B7!DMGe#6;WoW_ zNNL0OgH=1IAu1x|Vx5w^1+I^PTdK|6c$JmG7h58ZEx(D+IPsTPH{qQpm8l5Neck_`5{9k4+uhaBr+;|j~OWk`Z zs{Q`;IUXXeu6b%cY-h z@NljH4LtDA4M*E;st>t6w)8#Mlb4fgT}-ibGv?lSgzpV=AWu-XC(BkTXnO< z;Ntphh5O*}aC9-f1AOzG#KH|zml$PIdTq(@u%V%@p0F4+5Afvb5oQh#zZL@Zw6lP5 zN~%MK65FKK$G1RIMk^FRVE&(AKBdd{3trUJz)TJ(0DPLThEBHE*JZw%DBOSZ?Uz@4 zJY=B=u>=6PWb!oYR(WsUV4;qa)&gQB%!FJ23vE`ZDEucyh!uBJKAthg$cbWMW;X`L z|4VE=WU3Y44OgTU>rHbJ6w8zTojC4p7K(U`#ZaNTXvAj1e?Lt-@p1G1n%KSAP;m1a zn4Z3P0cQ4_OP~d4;=Uqhr-2OdCYQ(1HPVfSlpAb|f)^4zW~nz3W1CXko_OuU9TU&T z-6MmND_eUWCnDsH^6-!^k^JUOSCk}B+ebTbu7WP@7ISeCbTpUH6h9E^%?{SrrGhpQU|0Zi0UcH+FqBT% z_jPq20>ug}4f{v>A;2)Gb|v^BO3N>vsi&!46wEP~Mak1dW zC=$K^L$MpY@F%B4|2%FAl<3r+&U9;z`S|hPxBzLKJgWJqslS)zuk*uSOP+{-Bl;kO zKzGdju8D_6NPUgl!+#pcYkYYg7_+_n{0(F3khbu)W1`rQ3r;EXuYez;*Sa|`8nv3` z8%E59tCNr&><%j})! zxRNK`8kGo?ryps69e_nffx+W^u;ei_Ukg*P$FN%c z;*bhzgT_qiqxIiZV^?Vnjl_VC;_?kZ9_x>00;*2)N9zA-aJ$FUfI`O7k{&!E^{Xtu zqf3*h5)#2kGoo-wn57!EteVcrmQS3wEn?@a6sE127#J> z0pvQZ(2*4egW?&0f_PSQ2Cye=rv=yy_b`~V)vcaeVgVmGk!6+BPeXwIJ8CY2km-u; zA8mPI01d)>M$eOn32NLX9=FlbQK-~`Qs3Tooqos!9b#6?NQ5xo>rDlITIvJp1 z?zp@FmX($<@IdSN^5a}-a8yF8Z2=Z$B^^Ku{U1I|NHd#EK!{@KG3=GW zR~z-a-w44*eqeSs5e$FHLBZKrLYJ@!^OKMf+cytlD2x zG#%1zw_F7QV%;COEr7mLbDHDXgtHgxu77;5E;OmGKSiF!0m(t;@9(e4{RRx!z&AQ} zN9>TnBxu40qFSX3+NOCW_X-mvTPPGhTH6RhypbIX*0i3l+_8S74=T<0|Gw0l@a1nZ!(Gb4rh8vG#g#iSAr=o=C zb=OlS!MSmi6+dBX7Uq9#47q3YsXR{;(1OjBE1`yl2K0<) zyWBu(bbFOUadsr=5~js-o_TtblSmvh-@VI@775w(q*{Pk1>9#)a{-=)^B0c@UQ!6m z$1DB+Ile8zZ<$R5m*N7&#QM0c=Mqmxj_S1C3O#SViG9pt#zBn&y$vmmSv^)zZ#s8I zMh4^uA^j`pl2M5ATd!bn?UPlwI~Na%ii%);y||+?6Gz2)iCyH-w&VLJX$JcG#%oruqo!+qG+-8q_L(NfAc1)f&Bw>bs$+Fv0bO8uUd4~+H=!o-(^ zu9UCOR)}Yzy_p0c<9ge?;*ReBQJEUwY-?;zGg?a)1gtU^+Il+HsQOe2YS{lbz~ z1Gif_qjN8MBPkrDxF#nj(dgc$zYTkzkk!K{g|Ac^x~<7`FAx454}8*no00Vig%4Nh zvDN@1GPK|3sIxF8Ucj&6F%bic zFUxo4Y;bBS&RHO;uaCPFW`RFF{zkL=ohOJ4?OS~wBne;@+%9yKIzP#s4T*{IfVB@c z^Yp@=*s=NV08L?FV9=fU43aDm@}aFifjla909o_^Unj!{i`U6dip`A$RKIL4r@bEI zQ-fFZgBy5cfjGvFj7qc`F6u;~5}y*O4Z|3VyX?ig8&6w8zVw?#!a)cs*Q4hsa4oht z+Lm7V{iuZ`V_o+C8)@E~i`pDhQiw+h$%@ymN1ubijew^zxj%v$Mh@6XH?_J%5M zi)kcQ>xL>WBOBn&fZ_4U*xA{c$N4d;q56(GH~L8HV(uUpoEoG}|Al1p)GL^aC}kouBNJ5!dCF43nwWI!}ZuGWubI78LOD3XiqIG`*gUEVnBt zIsP^#ibu{Eela(shC8+!(Q-nEjfHt|aA4WH9%pXYx@i~)Wx}o#?dGQmk)hGZD5jvB zDJc}7dr#BXIOJ^IIchJ}aUV6bvw+&=xYw-~E`$auu5GM(d%oDJs)u4no6n-z=gWf+ zyhN5x`BwrJ4~_S^biEL@Bm)-X@}BY7;>orT9Ied0UF$b$O-)O46JVq@`^M$hCu)-z zB*~a)HJC3iNe4jzB;F7$wDn2I+0kGo{U)Ge_KQsD(~g@`UnQkZ$dM z$rX=B_tJvE@KcFIC`kRp_PXlKr)pK6fS{+%d_bJwi_ZP8C$lvhx~0ax_&{U1@AnD< zpah-T=La8)N#nmmN(G$<55-z+2%Ryqvl$GkSG~ezZo^n49O!(f;_W2>W^02TY=r=~ z2RWijD!2E_PoVas#-`78?&C!FZ$Hob>k0zdYmH`p*J(iF4o43SlhBTslosFtu(b}6 zhqRVeZyQ(6m(rg8pmRgMh+_1|g9B7R0u|!~ig0xxq;Swj9jAT}Ug3YY6#gMJVdC0K zpT7Ix`iSnnC-rhYS^O4v?}b;}U;3 zTFe|!;n;@~6%|4jm?DJvp0RuBy|z#ahoeC`l$dz4zpD8ZSotdPFnt68Sp8XnwkQI z{$2d&Pgp$NPTNqS%0oDV;lM(3e&`OHcN-#baV3MZk~E1DryS075GA`7Jxbt}J0g z&l@?u@bASp0vX}=mh+yLzw0Fx3J?^kG`$l4{#y2gNTYB+JJjK=(w!6z-To&5ZdRyiS$QuHS|nXgRcKT2vP67L+HB{GQnS3i3A z5ZdTGAkQ6L(wbkCM$sbK)QNqzCcS6D7+n$<Zt}Pb=pxroMRg{d(=YTYa|5;&ptJ-ks1i2j7LqJWyGCjJ}YGkEm z2?`ZgiTiH|LfhUox@Fmcke49>czy}jSLH5KkQRgNgNhda1$kVOi)h?mPzV7~0O+r6h*I zs)B*Td>dll_(PSfmh!Z+oEu3Ez2vZaS@&$C8?|PduywVjmcL6+78N;wb_3QFZ2N4+ zjI69bew*V}M=AAaWWE8xrp^cotZ#ttZ7E4@g$n8Fn)X{_ypwWHu#M5;`+)HFN?v;f zT#MY#qVE}<-OOqMtqb^A&dsZcHN-ey6Ar&XP(|5uF+wRtMO>h=wi|aOAm8UKug4lR zphO!^-KQeV6u5XQSD=L*)+XYl@F-ob(DL@p8_cA5zv+Xac>w}3Xl9}36;oadQ>erE z<9KB$flMAV#0`vMHPF9UKT3Cedkgc$q9}O`7?FeK6K;`jD^AwPJ_HUh=Fy_(LA)?0 z#WbxTqlM;V&?sdaPb4G|+erop#93CY63{F*77aVV9|AiK2oAU=HEx?KU&1SdwwZgs zFk$@qyu9d!wdA?6mK=h%On+)Ixgae~?mxkNf&NSa%ND}3Odqddj^Oy8V@f40rGH#bZ8VHwBCppT0?bGE-)36P?nx_)!8c)sE;SwbnrCl%%I_Uo;D?;rl@$6j=i z7gm?%^I*s}ooladDeNIC3 z(79GFSnD<)PB&e(R?g0%jyl@>XSlsP>1 zR>sDsUKHMvilkCCWO3Hpx7i3EyKKT1P9FU=N+C-1y}5mOuPNN3HnD0er8g|Pwdu5h zX0>*sCQ@pC5w3?Y^bTRe{$A}&G!8e}ivZJowliD4Ydl*Ky@YP9luL>_j6Tei4ufKI zVS=Orv>o!J_%O326ddT=d3P^%f=N`;xZ9y;J6VbC@6p-DkaMaWGFn;Ak>y2PGyCL^ zj^+M1>x|o4wHK8qcEk1urU>&{2R^&r)M3sbt)@zk7`%x%=kDN{I`fT~ChDay{WLR= z{q^uZk`s;6$BT7r2czNDnbpkpdw0+LC$39wN|?+rw-W1Z{_Uc(Zc@S_&2{K)?&+b? zcub9d-7Vr6;SjSPnZ{(+wEL5TMb+PYdv&$-_?Rsx2uSM!tugw(GsZ>6L{-ERO`wL^ z1Omm+60Z_+GWhJP*zli;*apksLdZuuc5g4W4AB;CHvbV0Ef4;X~2Z5=% z>E}029v*sz$a8i=X3!55`(wQbY5c+r0jvA#b;v>fN2(V7cdx~F#|-ue&`JQagPC~cKRF+!B#DXA0p(6@V78ihcwB~Xx&@@?$D_I4-@wM2oc|s- zolQz!b{%lCXb@Hf0~od9JllLBhVlKskBj8O4?Tv8)ERYjYq)y$s0bp;*S)iKVDqhF zqMOTB_T%9+(A6EuXpQG9y~?#$NbxHkbk0%Nn=!8Hn<2h@w>ORv@VDPMzDH$)20z|S zbav$EJgCKC%147cZJ(@!zL6lCMzE1;pmr<2d_#GvHqiUU$9g=2{RW4OhI|f+-19~D z3dyt0FMt%!dit?l9-~yOQf|3~h#l{hqyK0fp=n5N_@iOJ1yL9DxH7 zvHKx2h5q~Smk)Y83q3#EL?iI%Ae{8CG_HUv9kQ;hOs#jx^GOM5cvr{lORB%tQt$8V z@ipiv7BtYP(J3MMkDp5zr0Pz9yayK^!P@+OtSQ~~0sEMWC3oZO0wr=AsUDKzkxE`4 zhPw3cD@_i*pz~u7rrpt%an3ifEoEg73LI#`_(W|iWsbh? z$X1W8_DSB^cB2~tY-IshdLvDUikDJTq;i=OW?L;g#Y{r1ppgOT<;QW~^Hpkl9ajN3 z1~?B|o2B4%o!!axht!rVUV)4t0(>knTg7=YlNxOdw}r?1lnwfr(IDvrO!u9Kp3Uv& z&%cDVF;To4&|s8%Hn*9z**JJQaQ}nOeRN|Wx)OzUED?d~3brL%tcF_|_aR^kBk(8GbF@vdo&4FjUj~=15 zS%S0ApEGwurrcq z3@W5r?2jr+S&qyr{2;iZ7x$;EXgJ8I$=hes7AAj%Jy~#dbzw==8+~;pO0-mOW%`|oV+uz)`o~9e__|*E5 zNB-)J=Pw^@e*AJsDVsPL|2lE^+WuSMs9*cwmp0G6|BUNUHgPcQ_=l#)8PDJP<;~p} zgQ0BVV3-YuW{WeX>C$Fer4C{9NX6JAcY{JWrwnfg8{2)`MHZv zm9Lad91I+v-hJT3rz#%GCJqK{U<9Y>>57`NiMJVjB-kM}j^r_~S*dnq6C=vgq?W6N z$|ep5tfqI>i^?Vr2CQZTHB!nZE=FZZ&xXjDuzY0CG-)Pk#wnXPbeQFp?V8ofCJu&K zT@|I3qio_}nAKIatW?Zh*~G;_mK@?6B6a@Y=B#s#v&KI&(HV%;hu;^L)pZ^$e23=k^1%JU?`h77#VYCM9fo%uz93nAm+|Mq^LvL#5F5)A7>y^ zv_sj%!N{104(o~Zm9mM0kui7gB2tV8;!HMiFf!)OV9eoZWfN~R`bhNlkkUS{vr_HK zCWdaWb7Xt-6^^TH;$UP&wRnJ`{vi$q@|F?QNNEg+i-FGII(jyswof00<$-Hf=swQS zj8isoFf`jWtCdY03_Cu$XsbcYMA^i_FdM3B+1tU;x+4z8`2WhJP8^-PcEYVackRZb z2VT6%@r9$;9i6)vc*sxFYON#ZE}l5LaCFicdZf;nrju6Vp<|kEG<<4H-xgz^4AZes z9j1GK_pG}1p-*kn*f8`cuD7!Q4SWEO>%-y7x)M4x; z*`1-;U^eYDcQsC(p84+Q=AXXryploKryxYc0;mwiy~{vtvm+^hiTPbe~H# zldNFRrR?)N^2#dJx_W1cnd-qrYb zhE){ST9>k_U2+|?YF_SM)vVU4f9%K@x2fyUEYU8ZJ*G3%?;6c{@2W?+Bfq|PErQGQ zc2*RzMaPM{Lte2S`>eF?tgkG&dzqh=)>`gl+|#y3Rc&@1>h~@+;xx}NkCsiHJvghi zM$K00<=F4c>GJRjdsdoD*5Q`iA?pmgjviaDM?bFCd}n0Urj%yirR6va8=TczGebLrc8nnp z%QYJ`kFEZfyY~#54YqzP*+n(qx(;Pr{q8f%XZ{vhsrl9!=+vxp)Hd^Kel_U%b08T$ zxHqkHS~XcCGn&hQm31 z+OGK_k1XkXgK?EhSBc{cKL^ap89l03!Qi-#vQT}cJ{$5h`N&*R?T;YTB}(yZ@JFO zsp>l4kM}$-}zZB*fa18*DGM|K7jROv&!p~@oQX%0sh}~a2*6g z_2D}|tA%Rkc@0K&wv@)-)q>ZP;@7zDBY1~*bH_rD`t>U?@~mhFgZn5*ao-Ni{XDRK zx*fbe0|~XMGt5HYi=>pTC1>`5d8J6Dff4gzEw8X(#8x%G0tu|2o+Uf{w!?DuNm`py zzV7Z|s84vFiCL%*w`OIQp0fWS6?@T;h_zj%fxCBkB?KetX?*8rwNNh_!>_|(RJ~4V z{9P^7i>UK)Z)$jbo`EiLp7+=qdvJR0@)~K3&*@-af)smKF!Www{DS|l7VJy-#(o9N zJ_f8G&nt_?iHvQW-9sWHn7=an%cg50CTcK%^zYe@7N4$f+!)v1}mGrb`j$aPd^phsaH#29x5*Jr3c!&URjLf;+Pm#cyMEmsN0 zouRp;ok2TBXK>}jubTPX4X8BmYN7eVl@lYHq4>^EXK-JFQO!_F<8Nh&dz4oxLSkfP zXK;@jziR)8eXvRcmyYykoJU~<=QzCci|_m#V@SU;kNDLVO7gF-oLFTtQgKFyQC&+Y zjlZjf=BTcm$g$Ch2FEfnuSVcEWFNba=Gc&j4$W}xOCiDYU6lr2Ei|jShr>ue5`KwK z%u1d@^8GHx<{8?Zd4>M^46TpcqqwKFR$@N!|6{#fo}bXJJ>d=Mk>A)i~scYcspqb9Ug zvqlifBFMbbI1PE&p~tm#(C@xN!q!LY zaIxd;46O+}&-CX@AfZRE5VDE6%k#$d{b)ziL zc4OS;$HLsXvkV>V^Me!KWsYh^Y32`k%t|Xqbtt4HNU^=m7^>2=t_N7ny;Ge z^SP@T*K1Ixmo&=F$jARCyUu!CI&$6_uirZoN*W67RK zHb#kSR%_Z}Gx6t>AVmx*o0VJ(H#>@#%tY;K z#9-SD>%OYnv1Yb&1V(5f*C^s(ShiO@tUBun zb!8I=!}6-)VbxjBu`8Q680uYJi-PdOTFSvWbJCmaB!zCJu&XyLwUC z#K8z_VpZdnc#IHZeAiCD7`88o`*oC3cIe2rQWiKC?_gkr7{BXXj{c^eju0!mbkrMe zdM2z_jfl4yIzl$2h%v)y`qdxavUuMe_qrXtlbcfY3?ye5jNAWlwD*Z89&`q;W`m(@ z;$S@c?8&{4{ORJ*c?gQ1qIg~}%0W@wy=A;mjb+q2>b zEF^{$?{fx2eZ>(lh(pJCvtyc+aV%dekIBZ7rb&Ip5uFKSI78r`B^-&F#2X5bp%;LC zR)>uFvAVN;X}tMjy6c@5pVcAriX%7@aq6qLE__yN=B~}E?gJBpp;gcsIzkM6WCQnE zaYSbV8O{*6Th0+Mh#{jM>9ewotE*gEsl+%^pOs~`TuB>j9w``>B^3|d(JPyHo1r6Q zLy8zS^;xNQWfKR(YOo@x7Al)K82!D}arUcc#k{v2cJy~&;|(VqOQrZ^L@@M?Lymw! z3@JW85e$9fkRz@`-fH9hmSE@`ha3TeIHdFpNf|uDQYmEv*W2Xz9^`n}jyfQtv#mAC zGHi@Mhf2{4kn#7n<$ccaW}!;a)4|XPa>RAy+h-xAk;NOPcsDghw$6V24AN|>cQEVU zPN3yJ0=7z-P4(Vof4`O^U=U-5W|O?nsqfcv1PtP|son;iCVjuwEcX%DA@7XxY694u z(MQJB2t880M;{TC~ma}J0q>NYYH}ZkxKiLf%mCV>yYAzVzDV1R_FCE2&CnqBP@5Rv?&>x zyL&h;M-)RxzXqg?KH~myeR`ydN7EtRZ8L=Kih1}-=B_rWN4j@80v*ISDm@Kcx!dC5 z9?f`!ltwl?oZFEd&gV{?HsPJ&5s&)!GR!AFg5wgqzUaZp(0#jEi@V|UkK?onZ%8L2 z*AHfik3ff6UQ%YcKNAABTaLHlX?Z;@(xtq^rH<^0&d8N4M?wnv$Of*y+jO|KITOfm zhQQU^oxu^c7BcFQT0cA<9C01uH+mXuuXDUd&rGaHb*Z>&SPb;`WQ?Z;^eF=3@NTcc zaX&)u4-p5W*ZH{jt9KfRgOR;Gy*r+)(0d5P!RY;J+!N9}4aCK$EWte}-n+4TI`ZsC z;F?wa%PqKr#ruQGCJu&XJDz&ry&Gi{2P1bf9uK=$RCi^RO&p9~wc|MnWfN~R`iQ<= zF^<$TQMD_ZIPyv@R|}O*91N{<^`f$ggVC#YL`vDj#lXL?(ef&MGT1%-nu(fmnoGoG zd97-i)ygIghE|kTjGl7>Kzu5Gm?VHgV0W z{#_hIigqZQI2hUCLWev-rEKD0WX#>Wh!o?2IMdU_!N{09gE5Dvl})_O=p*AjCOuN^ zWL$@8S2i(p*G|SQR|}O*9E_}}77xr<*~G!f-tG*Il*WL#80hWJ=-GfeulJH2*R1M1 mN;6K`#KF*P*Q{1HaWJ%^v~rY991OFes+N@sUn!e782<&x!jdxp literal 0 HcmV?d00001 diff --git a/resources/profiles/Flashforge/flashforge_c5_buildplate_texture.png b/resources/profiles/Flashforge/flashforge_c5_buildplate_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..a5af30d0c50e510084d947ec14fbd07a91d636b3 GIT binary patch literal 92605 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%0DXTftTJOzV?dP}S8@aVjeDi!VNdslc@KpP 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 O&`{s(dg-;>kNyW9n}S#X literal 0 HcmV?d00001 diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.4 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.4 nozzle.json new file mode 100644 index 0000000000..9dda6e29d5 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.4 nozzle.json @@ -0,0 +1,313 @@ +{ + "type": "machine", + "setting_id": "GM001", + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.28", + "0.28", + "0.28", + "0.28" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 0.4 nozzle", + "nozzle_diameter": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 0.4 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.4", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "0.8", + "0.8", + "0.8", + "0.8" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "0", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.6 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.6 nozzle.json new file mode 100644 index 0000000000..dba82cc8a9 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.6 nozzle.json @@ -0,0 +1,315 @@ +{ + "type": "machine", + "setting_id": "GM001", + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [ + ], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.42", + "0.42", + "0.42", + "0.42" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 0.6 nozzle", + "nozzle_diameter": [ + "0.6", + "0.6", + "0.6", + "0.6" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 0.6 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.6", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "1.2", + "1.2", + "1.2", + "1.2" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "0", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [ + ], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.8 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.8 nozzle.json new file mode 100644 index 0000000000..429559534e --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 0.8 nozzle.json @@ -0,0 +1,313 @@ +{ + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [ + ], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.48", + "0.48", + "0.48", + "0.48" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 0.8 nozzle", + "nozzle_diameter": [ + "0.8", + "0.8", + "0.8", + "0.8" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 0.8 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.8", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "2", + "2", + "2", + "2" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "0", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [ + ], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.4 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.4 nozzle.json new file mode 100644 index 0000000000..f805363cfb --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.4 nozzle.json @@ -0,0 +1,311 @@ +{ + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.28", + "0.28", + "0.28", + "0.28" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 Pro 0.4 nozzle", + "nozzle_diameter": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5 Pro", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 Pro 0.4 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.4", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "0.8", + "0.8", + "0.8", + "0.8" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "1", + "support_chamber_temp_control": "1", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.6 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.6 nozzle.json new file mode 100644 index 0000000000..07243946f1 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.6 nozzle.json @@ -0,0 +1,313 @@ +{ + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [ + ], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.42", + "0.42", + "0.42", + "0.42" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 Pro 0.6 nozzle", + "nozzle_diameter": [ + "0.6", + "0.6", + "0.6", + "0.6" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5 Pro", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 Pro 0.6 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.6", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "1.2", + "1.2", + "1.2", + "1.2" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "1", + "support_chamber_temp_control": "1", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [ + ], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.8 nozzle.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.8 nozzle.json new file mode 100644 index 0000000000..fb1bf11248 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro 0.8 nozzle.json @@ -0,0 +1,313 @@ +{ + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [ + "0x0" + ], + "bed_mesh_max": "99999,99999", + "bed_mesh_min": "-99999,-99999", + "bed_mesh_probe_distance": "50,50", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "default_bed_type": "", + "default_filament_profile": [ + "Flashforge Generic PLA" + ], + "default_print_profile": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "disable_m73": "1", + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "360", + "extruder_clearance_height_to_rod": "60", + "extruder_clearance_radius": "92", + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "from": "system", + "gcode_flavor": "klipper", + "head_wrap_detect_zone": [ + ], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "inherits": "Flashforge Adventurer 5M Pro 0.4 Nozzle", + "instantiation": "true", + "is_custom_defined": "0", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";end_gcode\nG1 X150 Y150 E-1.2 F12000", + "machine_load_filament_time": "0", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "30000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "30000", + "20000" + ], + "machine_max_acceleration_y": [ + "30000", + "20000" + ], + "machine_max_acceleration_z": [ + "300", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_junction_deviation": [ + "0", + "0" + ], + "machine_max_speed_e": [ + "30", + "30" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "20", + "20" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M25", + "machine_start_gcode": ";start_gcode\nM140 S[bed_temperature_initial_layer_single]\nM106 P101 S0 ; L+R_PLA_Turbo_Fan_0-255\nM106 P2 S0 ; Center_Fresch_Air_Input_Fan_for_PLA30%_(80_0-255) \nM191 S0 ; Chamber temp. max65C\nM106 S0 ; Model_Fan_(Heat_Break_Cooler_80-255)100%=255\nM106 P3 S0 ; Filter_Unit_Fan_0-255(ABS=255)\nM104 S[nozzle_temperature_initial_layer]\nG90\nM83\nG1 Z5 F2400\nT[initial_extruder]\nM109 S[nozzle_temperature_initial_layer] T[initial_extruder]\nG1 X256 Y0 Z0.2 F6000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\nG1 X216 E10 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n;start_gcode end", + "machine_tool_change_time": "7", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.48", + "0.48", + "0.48", + "0.48" + ], + "max_resonance_avoidance_speed": "120", + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08" + ], + "min_resonance_avoidance_speed": "70", + "name": "Flashforge Creator 5 Pro 0.8 nozzle", + "nozzle_diameter": [ + "0.8", + "0.8", + "0.8", + "0.8" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "hardened_steel", + "nozzle_volume": "0", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printable_area": [ + "0x0", + "256x0", + "256x256", + "0x256" + ], + "printable_height": "256", + "printer_model": "Flashforge Creator 5 Pro", + "printer_notes": "", + "printer_settings_id": "Flashforge Creator 5 Pro 0.8 nozzle", + "printer_structure": "corexy", + "printer_technology": "FFF", + "printer_variant": "0.8", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "resonance_avoidance": "0", + "retract_before_wipe": [ + "100%", + "100%", + "100%", + "100%" + ], + "retract_length_toolchange": [ + "3", + "3", + "3", + "3" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "-0.8", + "-0.8", + "-0.8", + "-0.8" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "2", + "2", + "2", + "2" + ], + "retraction_minimum_travel": [ + "2", + "2", + "2", + "2" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "0", + "support_air_filtration": "0", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "1", + "template_custom_gcode": "", + "thumbnails": "140x110/PNG", + "thumbnails_format": "PNG", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "upward_compatible_machine": [ + ], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "version": "2.1.1.0", + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "z_offset": "0" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro.json new file mode 100644 index 0000000000..bf8cbf3702 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5 Pro.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Flashforge Creator 5 Pro", + "model_id": "Flashforge-Creator-5-Pro", + "nozzle_diameter": "0.4;0.6;0.8", + "machine_tech": "FFF", + "family": "Flashforge", + "bed_model": "flashforge_c5_buildplate_model.stl", + "bed_texture": "flashforge_c5_buildplate_texture.png", + "hotend_model": "", + "default_materials": "" +} diff --git a/resources/profiles/Flashforge/machine/Flashforge Creator 5.json b/resources/profiles/Flashforge/machine/Flashforge Creator 5.json new file mode 100644 index 0000000000..8d5ac253b7 --- /dev/null +++ b/resources/profiles/Flashforge/machine/Flashforge Creator 5.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Flashforge Creator 5", + "model_id": "Flashforge-Creator-5", + "nozzle_diameter": "0.4;0.6;0.8", + "machine_tech": "FFF", + "family": "Flashforge", + "bed_model": "flashforge_c5_buildplate_model.stl", + "bed_texture": "flashforge_c5_buildplate_texture.png", + "hotend_model": "", + "default_materials": "" +} diff --git a/resources/profiles/Flashforge/process/0.12mm Standard @FF C5.json b/resources/profiles/Flashforge/process/0.12mm Standard @FF C5.json new file mode 100644 index 0000000000..08ccf13d19 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.12mm Standard @FF C5.json @@ -0,0 +1,50 @@ +{ + "bridge_speed": "35", + "compatible_printers": [ + "Flashforge Creator 5 0.4 nozzle", + "Flashforge Creator 5 Pro 0.4 nozzle" + ], + "elefant_foot_compensation": "0.1", + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_print_height": "0.25", + "inner_wall_acceleration": "10000", + "instantiation": "true", + "internal_solid_infill_pattern": "rectilinear", + "is_custom_defined": "0", + "layer_height": "0.12", + "max_travel_detour_distance": "300", + "name": "0.12mm Standard @FF C5", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "overhang_1_4_speed": "50", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "25", + "prime_volume": "30", + "print_settings_id": "0.12mm Standard @FF C5", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "35", + "sparse_infill_pattern": "grid", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_interface_spacing": "0.2", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_flow": "105%", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "110%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.18mm Standard @FF C5 0.6 nozzle.json b/resources/profiles/Flashforge/process/0.18mm Standard @FF C5 0.6 nozzle.json new file mode 100644 index 0000000000..2ec1a21692 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.18mm Standard @FF C5 0.6 nozzle.json @@ -0,0 +1,63 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.6 nozzle", + "Flashforge Creator 5 Pro 0.6 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.62", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.18", + "line_width": "0.62", + "max_travel_detour_distance": "300", + "name": "0.18mm Standard @FF C5 0.6 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.62", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "print_settings_id": "0.18mm Standard @FF C5 0.6 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.62", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_interface_bottom_layers": "0", + "support_line_width": "0.62", + "support_object_xy_distance": "0.35", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.62", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.20mm Standard @FF C5.json b/resources/profiles/Flashforge/process/0.20mm Standard @FF C5.json new file mode 100644 index 0000000000..f740a590b7 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.20mm Standard @FF C5.json @@ -0,0 +1,48 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.4 nozzle", + "Flashforge Creator 5 Pro 0.4 nozzle" + ], + "elefant_foot_compensation": "0.1", + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_print_height": "0.25", + "inner_wall_acceleration": "10000", + "instantiation": "true", + "internal_solid_infill_pattern": "rectilinear", + "is_custom_defined": "0", + "max_travel_detour_distance": "300", + "name": "0.20mm Standard @FF C5", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "overhang_1_4_speed": "50", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "40", + "print_settings_id": "0.20mm Standard @FF C5", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_pattern": "grid", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_interface_spacing": "0.2", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.24mm Standard @FF C5.json b/resources/profiles/Flashforge/process/0.24mm Standard @FF C5.json new file mode 100644 index 0000000000..5a59cd51d5 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.24mm Standard @FF C5.json @@ -0,0 +1,52 @@ +{ + "bridge_speed": "35", + "compatible_printers": [ + "Flashforge Creator 5 0.4 nozzle", + "Flashforge Creator 5 Pro 0.4 nozzle" + ], + "elefant_foot_compensation": "0.1", + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_print_height": "0.25", + "inner_wall_acceleration": "10000", + "inner_wall_speed": "230", + "instantiation": "true", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "230", + "is_custom_defined": "0", + "layer_height": "0.24", + "max_travel_detour_distance": "300", + "name": "0.24mm Standard @FF C5", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "overhang_1_4_speed": "50", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "print_settings_id": "0.24mm Standard @FF C5", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "230", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_interface_spacing": "0.2", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.30mm Standard @FF C5 0.6 nozzle.json b/resources/profiles/Flashforge/process/0.30mm Standard @FF C5 0.6 nozzle.json new file mode 100644 index 0000000000..1db533beb4 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.30mm Standard @FF C5 0.6 nozzle.json @@ -0,0 +1,65 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.6 nozzle", + "Flashforge Creator 5 Pro 0.6 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.62", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.3", + "line_width": "0.62", + "max_travel_detour_distance": "300", + "name": "0.30mm Standard @FF C5 0.6 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.62", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "print_settings_id": "0.30mm Standard @FF C5 0.6 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.62", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_line_width": "0.62", + "support_object_xy_distance": "0.35", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.62", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.32mm Standard @FF C5 0.8 nozzle.json b/resources/profiles/Flashforge/process/0.32mm Standard @FF C5 0.8 nozzle.json new file mode 100644 index 0000000000..c8caa9ee02 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.32mm Standard @FF C5 0.8 nozzle.json @@ -0,0 +1,66 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.6 nozzle", + "Flashforge Creator 5 Pro 0.6 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.82", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.32", + "line_width": "0.82", + "max_travel_detour_distance": "300", + "name": "0.32mm Standard @FF C5 0.8 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.82", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "55", + "print_settings_id": "0.32mm Standard @FF C5 0.8 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.82", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_line_width": "0.82", + "support_object_xy_distance": "0.35", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.82", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.42mm Standard @FF C5 0.6 nozzle.json b/resources/profiles/Flashforge/process/0.42mm Standard @FF C5 0.6 nozzle.json new file mode 100644 index 0000000000..16e44f7573 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.42mm Standard @FF C5 0.6 nozzle.json @@ -0,0 +1,65 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.6 nozzle", + "Flashforge Creator 5 Pro 0.6 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.62", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.42", + "line_width": "0.62", + "max_travel_detour_distance": "300", + "name": "0.42mm Standard @FF C5 0.6 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.62", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "print_settings_id": "0.42mm Standard @FF C5 0.6 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.62", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_line_width": "0.62", + "support_object_xy_distance": "0.35", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.62", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.48mm Standard @FF C5 0.8 nozzle.json b/resources/profiles/Flashforge/process/0.48mm Standard @FF C5 0.8 nozzle.json new file mode 100644 index 0000000000..9c752fc3a1 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.48mm Standard @FF C5 0.8 nozzle.json @@ -0,0 +1,66 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.8 nozzle", + "Flashforge Creator 5 Pro 0.8 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.82", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.48", + "line_width": "0.82", + "max_travel_detour_distance": "300", + "name": "0.48mm Standard @FF C5 0.8 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.82", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "55", + "print_settings_id": "0.48mm Standard @FF C5 0.8 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.82", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_line_width": "0.82", + "support_object_xy_distance": "0.35", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.82", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} diff --git a/resources/profiles/Flashforge/process/0.4mm Standard @FF C5 0.8 nozzle.json b/resources/profiles/Flashforge/process/0.4mm Standard @FF C5 0.8 nozzle.json new file mode 100644 index 0000000000..cdb2317023 --- /dev/null +++ b/resources/profiles/Flashforge/process/0.4mm Standard @FF C5 0.8 nozzle.json @@ -0,0 +1,66 @@ +{ + "compatible_printers": [ + "Flashforge Creator 5 0.8 nozzle", + "Flashforge Creator 5 Pro 0.8 nozzle" + ], + "enable_arc_fitting": "1", + "enable_extra_bridge_layer": "external_bridge_only", + "enable_prime_tower": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "filter_out_gap_fill": "0.1", + "from": "system", + "gap_fill_target": "topbottom", + "gap_infill_speed": "150", + "infill_wall_overlap": "15%", + "inherits": "0.20mm Standard @Flashforge AD5M Pro 0.4 Nozzle", + "initial_layer_infill_speed": "55", + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "initial_layer_speed": "35", + "inner_wall_acceleration": "10000", + "inner_wall_line_width": "0.82", + "inner_wall_speed": "150", + "instantiation": "true", + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_pattern": "rectilinear", + "internal_solid_infill_speed": "150", + "is_custom_defined": "0", + "layer_height": "0.4", + "line_width": "0.82", + "max_travel_detour_distance": "300", + "name": "0.4mm Standard @FF C5 0.8 nozzle", + "only_one_wall_top": "1", + "ooze_prevention": "1", + "outer_wall_line_width": "0.82", + "outer_wall_speed": "120", + "overhang_1_4_speed": "50", + "overhang_3_4_speed": "15", + "precise_outer_wall": "0", + "preheat_time": "20", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "55", + "print_settings_id": "0.4mm Standard @FF C5 0.8 nozzle", + "seam_gap": "15%", + "seam_slope_conditional": "1", + "seam_slope_inner_walls": "1", + "small_perimeter_speed": "30", + "sparse_infill_line_width": "0.82", + "sparse_infill_pattern": "grid", + "sparse_infill_speed": "100", + "standby_temperature_delta": "-80", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "0", + "support_line_width": "0.82", + "support_object_xy_distance": "0.35", + "support_top_z_distance": "0.2", + "support_type": "tree(auto)", + "top_shell_layers": "3", + "top_surface_line_width": "0.82", + "top_surface_speed": "150", + "version": "2.1.1.0", + "wipe_tower_cone_angle": "12", + "wipe_tower_extra_rib_length": "10", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "cone" +} From d37444b34a69c7902b6489039a54aace0acdc651 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Sun, 10 May 2026 16:30:36 +0200 Subject: [PATCH 036/127] K2 Plus/K2: add print area bounding box for adaptive bed mesh (#13290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * K2 Plus: add print area bounding box for adaptive bed mesh The K2 firmware reads MINX/MINY/MAXX/MAXY gcode comments to determine the adaptive bed mesh area. Without these, it falls back to full bed mesh even when calibration is enabled. K2 Pro also reads these comments (its profiles already had them). Signed-off-by: Igor Mammedov * K2: add print area bounding box for adaptive bed mesh Same change as K2 Plus — prepend MINX/MINY/MAXX/MAXY gcode comments so firmware can determine the adaptive bed mesh area. K2 Pro already had these. Signed-off-by: Igor Mammedov * Creality: bump profile version to 02.03.02.72 Signed-off-by: Igor Mammedov --------- Signed-off-by: Igor Mammedov Co-authored-by: SoftFever --- resources/profiles/Creality.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json | 2 +- resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json | 2 +- .../profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json | 2 +- .../profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json | 2 +- .../profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json | 2 +- .../profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/profiles/Creality.json b/resources/profiles/Creality.json index b95688e15d..3d3536377b 100644 --- a/resources/profiles/Creality.json +++ b/resources/profiles/Creality.json @@ -1,6 +1,6 @@ { "name": "Creality", - "version": "02.03.02.71", + "version": "02.03.02.72", "force_update": "0", "description": "Creality configurations", "machine_model_list": [ diff --git a/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json index 4cb1df1038..66ebd4864d 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.2 nozzle.json @@ -86,7 +86,7 @@ "5" ], "machine_pause_gcode": "PAUSE", - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", "machine_unload_filament_time": "0", "manual_filament_change": "0", "nozzle_type": "hardened_steel", diff --git a/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json index ace8b15990..324655c5ba 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.4 nozzle.json @@ -86,7 +86,7 @@ "5" ], "machine_pause_gcode": "PAUSE", - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", "machine_unload_filament_time": "0", "manual_filament_change": "0", "nozzle_type": "hardened_steel", diff --git a/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json index d325dbcf52..3d9b7cb17b 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.6 nozzle.json @@ -86,7 +86,7 @@ "5" ], "machine_pause_gcode": "PAUSE", - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", "machine_unload_filament_time": "0", "manual_filament_change": "0", "nozzle_type": "hardened_steel", diff --git a/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json index 8b5f55c395..9a1725b989 100644 --- a/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 0.8 nozzle.json @@ -86,7 +86,7 @@ "5" ], "machine_pause_gcode": "PAUSE", - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM104 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y130 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y130 F6000\nG1 E0.8 F300\nG1 X0 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG1 X130 Y0 E9 F{filament_max_volumetric_speed[initial_extruder]/0.3*60}\nG92 E0\nG1 Z1 F600", "machine_unload_filament_time": "0", "manual_filament_change": "0", "nozzle_type": "hardened_steel", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json index 7e476f5430..eb4441a797 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.2 nozzle.json @@ -136,7 +136,7 @@ "default_filament_profile": [ "Creality Generic PLA @K2-all" ], - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", "machine_end_gcode": "END_PRINT", "machine_pause_gcode": "PAUSE", "change_filament_gcode": "G2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\nG1 X0 Y245 F30000\nG1 Z{z_after_toolchange} F600", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json index 2a5d6523aa..d1ff209b29 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.4 nozzle.json @@ -136,7 +136,7 @@ "default_filament_profile": [ "Creality Generic PLA @K2-all" ], - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", "machine_end_gcode": "END_PRINT", "machine_pause_gcode": "PAUSE", "change_filament_gcode": "G2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\nG1 X0 Y245 F30000\nG1 Z{z_after_toolchange} F600", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json index 1727eaf930..5b1373c4eb 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.6 nozzle.json @@ -136,7 +136,7 @@ "default_filament_profile": [ "Creality Generic PLA @K2-all" ], - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", "machine_end_gcode": "END_PRINT", "machine_pause_gcode": "PAUSE", "change_filament_gcode": "G2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\nG1 X0 Y245 F30000\nG1 Z{z_after_toolchange} F600", diff --git a/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json index 8f3226d4dc..f058cc8ccf 100644 --- a/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality K2 Plus 0.8 nozzle.json @@ -136,7 +136,7 @@ "default_filament_profile": [ "Creality Generic PLA @K2-all" ], - "machine_start_gcode": "M140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", + "machine_start_gcode": ";SET PRINT AREA MIN AND MAX COORDINATES TO ENABLE ADAPTIVE PROBING\n; MINX = {first_layer_print_min[0]}\n; MINY = {first_layer_print_min[1]}\n; MAXX = {first_layer_print_max[0]}\n; MAXY = {first_layer_print_max[1]}\nM140 S0\nM104 S0 \nSTART_PRINT EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TEMP=[bed_temperature_initial_layer_single]\nT[initial_no_support_extruder]\nM109 S[nozzle_temperature_initial_layer]\nM204 S2000\nG1 Z3 F600\nM83\nG1 Y150 F12000\nG1 X0 F12000\nG1 Z0.2 F600\nG1 X0 Y150 F6000\nG1 X0 Y0 E15 F6000\nG1 X150 Y0 E15 F6000\nG92 E0\nG1 Z1 F600", "machine_end_gcode": "END_PRINT", "machine_pause_gcode": "PAUSE", "change_filament_gcode": "G2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\nG1 X0 Y245 F30000\nG1 Z{z_after_toolchange} F600", From f3fe37eab387533b5b1c3bf15cea5cd3df648799 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 10 May 2026 23:08:40 +0800 Subject: [PATCH 037/127] Remap paint after dovetail cut --- src/libslic3r/CutUtils.cpp | 71 +++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 9fc6f13c2a..fbc4d93c3e 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -451,15 +451,23 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs& objects) for (ModelObject* mo : objects) { TriangleMesh mesh; // Merge all SolidPart but not Connectors + std::vector> saved_paintings; for (const ModelVolume* mv : mo->volumes) { if (mv->is_model_part() && !mv->is_cut_connector()) { TriangleMesh m = mv->mesh(); m.transform(mv->get_matrix()); mesh.merge(m); + saved_paintings.emplace_back(mv->save_painting()); + if (saved_paintings.back()) { + saved_paintings.back()->mesh = std::move(m); + } } } if (!mesh.empty()) { - ModelVolume* new_volume = mo->add_volume(mesh); + ModelVolume* new_volume = mo->add_volume(std::move(mesh)); + for (const auto& saved_painting : saved_paintings) { + new_volume->restore_painting(saved_painting, true); + } new_volume->name = mo->name; // Delete all merged SolidPart but not Connectors for (int i = int(mo->volumes.size()) - 2; i >= 0; --i) { @@ -583,6 +591,11 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran tmp_model.add_object(*cut_mo); ModelObject* tmp_object = tmp_model.objects.front(); + // Store source volume id so we could track them back after the cut + for (int i = 0; i < cut_mo->volumes.size(); i++) { + tmp_object->volumes[i]->cut_info.source_volume = cut_mo->volumes[i]->id(); + } + auto add_volumes_from_cut = [](ModelObject* object, const ModelObjectCutAttribute attribute, const Model& tmp_model_for_cut) { const auto& volumes = tmp_model_for_cut.objects.front()->volumes; for (const ModelVolume* volume : volumes) @@ -603,6 +616,20 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran tmp_model_for_cut.add_object(*cut.perform_with_plane().front()); assert(!tmp_model_for_cut.objects.empty()); + // Track back the volume id + for (const auto v : tmp_model_for_cut.objects.front()->volumes) { + auto& src_id = v->cut_info.source_volume; + if (src_id.valid()) { + // Find the src volume + for (const auto volume : object->volumes) { + if (src_id == volume->id()) { + src_id = volume->cut_info.source_volume; + break; + } + } + } + } + object->clear_volumes(); add_volumes_from_cut(object, add_volumes_attribute, tmp_model_for_cut); reset_instance_transformation(object, m_instance); @@ -663,6 +690,48 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran // this part can be added to the upper object now add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + // Paint volumes + if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) { + const auto instance_matrix = cut_mo->instances[m_instance]->get_transformation().get_matrix_no_offset(); + std::map> saved_paintings; + auto get_painting = [&saved_paintings, &cut_mo, &instance_matrix](const ObjectID& volume_id) -> std::optional& { + const auto it = saved_paintings.find(volume_id); + if (it != saved_paintings.end()) { + return it->second; + } + + // Export paintings from volume + const auto volume = std::find_if(cut_mo->volumes.begin(), cut_mo->volumes.end(), + [&volume_id](const ModelVolume* v) { return volume_id == v->id(); }); + + std::optional saved_painting = (*volume)->save_painting(); + if (saved_painting) { + // Transform mesh to cut space (same transform as process_volume_cut applies) + const auto volume_matrix = (*volume)->get_matrix(); + saved_painting->mesh.transform(instance_matrix * volume_matrix, true); + } + + saved_paintings.emplace(volume_id, std::move(saved_painting)); + + return saved_paintings[volume_id]; + }; + + auto paint_volumes = [&get_painting](const ModelObject* object) { + for (const auto volume : object->volumes) { + if (volume->cut_info.source_volume.valid()) { + volume->restore_painting(get_painting(volume->cut_info.source_volume)); + } + } + }; + + if (m_attributes.has(ModelObjectCutAttribute::KeepUpper)) { + paint_volumes(upper); + } + if (m_attributes.has(ModelObjectCutAttribute::KeepLower)) { + paint_volumes(lower); + } + } + ModelObjectPtrs cut_object_ptrs; if (keep_as_parts) { From c0ae2bda998a43ca5395ac3a00afb2c653176f8d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 11 May 2026 01:32:59 +0800 Subject: [PATCH 038/127] Fix DropDown submenus on Linux/Wayland (#13563) Hovering a group item (e.g. "Generic" in the filament list) now opens its submenu correctly. The dropdown stays usable while moving the cursor between the parent list and the submenu, and dismisses normally when the user clicks outside. --- src/slic3r/GUI/Widgets/DropDown.cpp | 37 ++++++++++++++++++++++++++ src/slic3r/GUI/Widgets/DropDown.hpp | 2 ++ src/slic3r/GUI/Widgets/PopupWindow.cpp | 3 ++- src/slic3r/GUI/Widgets/PopupWindow.hpp | 6 +++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index 59832067c8..d698f9f7dc 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -563,6 +563,34 @@ void DropDown::messureSize() subDropDown->text_off = text_off; subDropDown->use_content_width = true; subDropDown->Create(GetParent()); +#ifdef __WXGTK__ + // Orca: Keep the wx parent as the combobox so wxPopupTransientWindow installs + // its capture handlers on the main dropdown, but make the native GTK + // popup transient for the currently open popup to satisfy Wayland's + // xdg-shell rule that a popup's parent must be the topmost mapped popup. + gtk_window_set_transient_for(GTK_WINDOW(subDropDown->GetHandle()), GTK_WINDOW(GetHandle())); + // Orca: On Wayland, while the sub holds an xdg_popup grab, motion events for + // the cursor over main may not be delivered (Mutter drops motion + // outside the grabbing surface). Poll on idle and synthesize a + // mouseMove on main so its hover highlight tracks and it can dismiss + // the sub when the cursor leaves the parent (group) item. + DropDown* sub = subDropDown; + sub->Bind(wxEVT_IDLE, [sub](wxIdleEvent& e) { + e.Skip(); + if (!sub->IsShown() || !sub->mainDropDown->IsShown()) + return; + wxPoint screen_pt = wxGetMousePosition(); + if (sub->GetScreenRect().Contains(screen_pt) || !sub->mainDropDown->GetScreenRect().Contains(screen_pt)) + return; + wxPoint main_pt = sub->mainDropDown->ScreenToClient(screen_pt); + wxMouseEvent ev(wxEVT_MOTION); + ev.SetEventObject(sub->mainDropDown); + ev.m_x = main_pt.x; + ev.m_y = main_pt.y; + sub->mainDropDown->mouseMove(ev); + e.RequestMore(); + }); +#endif subDropDown->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { e.SetEventObject(this); e.SetId(GetId()); @@ -759,6 +787,15 @@ void DropDown::Dismiss() PopupWindow::Dismiss(); } +bool DropDown::ShouldDismissOnTopWindowDeactivate() +{ + // On Wayland, mapping a chained xdg_popup with grab makes the parent + // toplevel inactive, which would otherwise cascade-dismiss the whole + // chain. Skip when our chain peer is shown. + return !((mainDropDown && mainDropDown->IsShown()) || + (subDropDown && subDropDown->IsShown())); +} + void DropDown::OnDismiss() { if (mainDropDown) { diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index 8b7ab19d61..639a13e526 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -110,6 +110,8 @@ protected: void OnDismiss() override; + bool ShouldDismissOnTopWindowDeactivate() override; + private: void paintEvent(wxPaintEvent& evt); void paintNow(); diff --git a/src/slic3r/GUI/Widgets/PopupWindow.cpp b/src/slic3r/GUI/Widgets/PopupWindow.cpp index a8412bcfc9..8fb1cda774 100644 --- a/src/slic3r/GUI/Widgets/PopupWindow.cpp +++ b/src/slic3r/GUI/Widgets/PopupWindow.cpp @@ -86,7 +86,8 @@ void PopupWindow::OnMouseEvent2(wxMouseEvent &evt) void PopupWindow::topWindowActiavate(wxActivateEvent &event) { event.Skip(); - if (!event.GetActive() && IsShown()) DismissAndNotify(); + if (!event.GetActive() && IsShown() && ShouldDismissOnTopWindowDeactivate()) + DismissAndNotify(); } #endif diff --git a/src/slic3r/GUI/Widgets/PopupWindow.hpp b/src/slic3r/GUI/Widgets/PopupWindow.hpp index 55231accce..45afea8213 100644 --- a/src/slic3r/GUI/Widgets/PopupWindow.hpp +++ b/src/slic3r/GUI/Widgets/PopupWindow.hpp @@ -17,6 +17,12 @@ public: #ifdef __WXMSW__ void BindUnfocusEvent(); #endif +protected: + // Orca: Hook so derived classes (e.g. DropDown chains) can skip auto-dismissal + // when the toplevel deactivates as a side effect of their own popup grab + // (notably on Wayland, where mapping a chained xdg_popup with grab makes + // the parent toplevel briefly inactive). + virtual bool ShouldDismissOnTopWindowDeactivate() { return true; } private: #ifdef __WXOSX__ void OnMouseEvent2(wxMouseEvent &evt); From 3a52fb3b3ab6b489eb55672501f6131396de2694 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 11 May 2026 01:40:20 +0800 Subject: [PATCH 039/127] Fixed an issue that X2D 0.4 don't have default material --- resources/profiles/BBL.json | 2 +- resources/profiles/BBL/machine/Bambu Lab X2D.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 0157f07c91..55f5dc798e 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -1,7 +1,7 @@ { "name": "Bambulab", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json", - "version": "02.01.00.11", + "version": "02.01.00.12", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ diff --git a/resources/profiles/BBL/machine/Bambu Lab X2D.json b/resources/profiles/BBL/machine/Bambu Lab X2D.json index d34c8717d3..df2ca2c45b 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X2D.json +++ b/resources/profiles/BBL/machine/Bambu Lab X2D.json @@ -14,5 +14,5 @@ "machine_tech": "FFF", "model_id": "N6", "not_support_bed_type": "Cool Plate", - "default_materials": "Bambu PLA Matte @BBL X2D;Bambu PLA Basic @BBL X2D;Bambu TPU 95A @BBL X2D;Generic TPU @BBL X2D;Bambu PETG Basic @BBL X2D;Bambu PETG HF @BBL X2D;Bambu ABS @BBL X2D;Bambu PC @BBL X2D" + "default_materials": "Bambu PLA Matte @BBL X2D;Bambu PLA Matte @BBL X2D 0.4 nozzle;Bambu PLA Basic @BBL X2D;Bambu PLA Basic @BBL X2D 0.4 nozzle;Bambu TPU 95A @BBL X2D;Bambu TPU 95A @BBL X2D 0.4 nozzle;Generic TPU @BBL X2D;Generic TPU @BBL X2D 0.4 nozzle;Bambu PETG Basic @BBL X2D;Bambu PETG Basic @BBL X2D 0.4 nozzle;Bambu PETG HF @BBL X2D;Bambu PETG HF @BBL X2D 0.4 nozzle;Bambu ABS @BBL X2D;Bambu ABS @BBL X2D 0.4 nozzle;Bambu PC @BBL X2D;Bambu PC @BBL X2D 0.4 nozzle" } From f8db5b8ba3dd79a58ff721d3d97816c7c4e44408 Mon Sep 17 00:00:00 2001 From: pghwinter <123715108+pghwinter@users.noreply.github.com> Date: Sun, 10 May 2026 14:30:24 -0400 Subject: [PATCH 040/127] Adjust creality generic ASA first layer temp from 60c to 100c (#13558) Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- resources/profiles/Creality/filament/fdm_filament_asa.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/profiles/Creality/filament/fdm_filament_asa.json b/resources/profiles/Creality/filament/fdm_filament_asa.json index 019a07c68d..2dbf5b233c 100644 --- a/resources/profiles/Creality/filament/fdm_filament_asa.json +++ b/resources/profiles/Creality/filament/fdm_filament_asa.json @@ -16,6 +16,9 @@ "textured_plate_temp": [ "100" ], + "textured_plate_temp_initial_layer": [ + "100" + ], "cool_plate_temp_initial_layer": [ "105" ], From 133dc1c8e5f80d0055595a26878b85789e9b0b0d Mon Sep 17 00:00:00 2001 From: yw4z Date: Mon, 11 May 2026 02:16:13 +0300 Subject: [PATCH 041/127] Printer selection dialog redesign (#12248) * init * remove debug * update * cleanup * update * animate sidebar and search bar when reduce motion not enabled * add custom snappy scrolling to fix lags * cleanup * update * scroll to vendor after layout change * improve snapping on events * update * match UI of setup guide --- resources/web/guide/21/21.css | 400 ++++++++++++++++++++++----- resources/web/guide/21/21.js | 96 ++++++- resources/web/guide/21/index.html | 230 +++++++++++++++- resources/web/guide/24/24.css | 426 +++++++++++++++++++++++------ resources/web/guide/24/24.js | 107 +++++++- resources/web/guide/24/index.html | 231 +++++++++++++++- resources/web/guide/css/common.css | 25 +- resources/web/guide/css/dark.css | 14 - resources/web/include/global.css | 22 +- src/slic3r/GUI/WebGuideDialog.cpp | 5 + 10 files changed, 1336 insertions(+), 220 deletions(-) diff --git a/resources/web/guide/21/21.css b/resources/web/guide/21/21.css index b370a94879..6ed2682533 100644 --- a/resources/web/guide/21/21.css +++ b/resources/web/guide/21/21.css @@ -1,20 +1,34 @@ #Content { overflow-y:auto; - padding: 32px; /* ORCA Specify & Reduce horizontal paddings to fit 4 items per row */ + padding: 0 10px 0 20px; /* ORCA Specify & Reduce horizontal paddings to fit 4 items per row */ + height: 100%; +} + +.OneVendorBlock { + position: relative; + margin-bottom: 7px; +} + +.OneVendorBlock:last-of-type { + margin-bottom: 36px; } .BlockBanner { + position: sticky; + top: 0; + left: 0; padding: 0px; - border-bottom:#009688 1px solid; + border-bottom: 2px solid var(--main-color); width: 100%; display: flex; - justify-content:space-between; align-items: center; + z-index: 100; + background-color: var(--bg-color-secondary); + box-sizing: border-box; } - .BannerBtns { display: flex; @@ -22,53 +36,137 @@ justify-content: space-around; align-items: center; text-align: center; - margin-right: 0px; /* ORCA align buttons with end of horizontal separator/line */ + margin-right: 5px; /* ORCA align buttons with end of horizontal separator/line */ + margin-left: auto; } .BlockBanner a { - display: inline-block; - background-color:#009688; - line-height: 40px; - height: 40px; - padding: 0px 24px; - color: #fff; + line-height: 30px; + height: 30px; + font-size: 17px; + font-weight: 600; + padding: 0px 10px; + color: var(--fg-color-text); +} + +.BlockBanner .modelCount { + margin: 0 15px 0 auto; + font-size: 14px; + line-height: 14px; + height: 15px; + color: var(--fg-color-label); +} + +.VendorCheckbox { + transform: scale(1.3); } .PrinterArea { - padding: 10px 0px; /* ORCA Reduce horizontal paddings to fit 4 items per row */ - display: flex; - flex-wrap: wrap; + padding: 7px 0px; /* ORCA Reduce horizontal paddings to fit 4 items per row */ + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 7px; } .PrinterBlock { - width: 160px; + display: flex; + align-items: center; text-align: center; - padding: 10px; + flex-direction: column; + gap:10px; + padding: 15px 10px 10px 10px; + background-color: var(--bg-color-secondary); + position: relative; + border: 1px solid transparent } -.PImg -{ +.PrinterBlock:hover { + background-color: var(--focus-bg-item); + border-color:var(--main-color); +} + +.PImg { width:120px; /* ORCA use covers as 120x120px but use source file as 240x240 for better quality on hidpi */ height:120px; /* ORCA fit image to fill frame */ - padding:10px 20px /* ORCA use less vertical padding */ +} + +.PrinterInfo, +.PrinterInfoMark { + position: absolute; + right: 4px; + top: 4px; + opacity: 0; + border-radius: 11px; + line-height: 19px; + font-size: 14px; +} + +.PrinterInfo { + --card-animation-delay: .8s; /* open info with delay on list / compact view to prevent them appear while mouse movements */ + --card-info-height: fit-content; + left: 4px; + width: auto; + z-index: 9998; + height: var(--card-info-height); + border-color: var(--border-color); + background: var(--bg-color); + padding: 10px; + text-align: left; + color: var(--fg-color-text); + pointer-events: none; +} + +#Content[layout="2"] .PrinterInfo { + --card-animation-delay: .3s; + --card-info-height: 116px; +} + +.PrinterInfo .title {font-weight: 700} +.PrinterInfo .value {font-weight: 400} + +.PrinterInfoMark:hover + .PrinterInfo { + animation: infoCard 0s forwards var(--card-animation-delay); +} + +@keyframes infoCard {100% { + opacity: 1; + box-shadow: 0 5px 10px rgba(0,0,0,.2); +}} + +.PrinterInfoMark { + width: 20px; + height: 20px; + background: var(--main-color); + border: 1px solid var(--main-color); + z-index: 9999; + color: #FFF; + text-align: center; +} + +.PrinterBlock:hover .PrinterInfoMark { + opacity: 1; +} + +.PrinterBlock:hover .PrinterInfoMark:hover { + background: var(--main-color-hover); } .ModelCheckBox { - flex: 0 0 18px; /* ORCA match checkbox style and size */ - margin: 10px 5px 0 0; - width: 18px; - height: 18px; - background-image: url("../img/emptycheck.svg"); - background-size: cover; + position: absolute; + height: 6px; + bottom: 0; + left: 10%; + width: 80%; + background: var(--button-bg-hover) } .ModelCheckBox.ModelCheckBoxSelected { - background-image: url("../img/greencheck.svg"); + background: var(--main-color-fixed) } img.ModelThumbnail @@ -79,8 +177,11 @@ img.ModelThumbnail .PName { - font-weight: 700; - text-align:left; + font-weight: 600; + line-height: 20px; /* ORCA */ + text-align: center; + width: 100%; + color: var(--fg-color-text); } .pNozzel @@ -98,6 +199,79 @@ img.ModelThumbnail margin-right: 5px; } +.LayoutSelector { + position: absolute; + right:21px; + top:14px; +} + +.LayoutSelector .TabGroup { + display: flex; + padding: 2px; + gap: 2px; + border-radius: 6px; + background-color: var(--bg-color-alt); +} + +.LayoutSelector .icon16 { + opacity: .8; +} + +.LayoutSelector .TabButton { + padding: 7px; + border-radius: 4px; +} + +.LayoutSelector .TabButton.selected {background: var(--main-color)} +.LayoutSelector .TabButton.selected:hover {background: var(--main-color-hover)} +.LayoutSelector .TabButton.selected .icon16 {background: #FFF} + +.LayoutSelector .TabButton:nth-of-type(1) .icon16 {--icon-url: var(--icon-layout-list)} +.LayoutSelector .TabButton:nth-of-type(2) .icon16 {--icon-url: var(--icon-layout-compact)} +.LayoutSelector .TabButton:nth-of-type(3) .icon16 {--icon-url: var(--icon-layout-cover)} + +/* LAYOUT */ +#Content[layout="compact-list"] .PrinterArea { + grid-template-columns: repeat(4, 1fr); +} + +#Content[layout="compact-list"] .PImg { + display: none; +} + +#Content[layout="compact-list"] .OneVendorBlock { + margin-bottom: 15px; +} + +#Content[layout="compact-cover"] .PrinterArea { + grid-template-columns: repeat(3, 1fr); +} + +#Content[layout="compact-cover"] .PImg { + width: 60px; + min-width: 60px; + height: 60px; +} + +#Content[layout|="compact"] .PName { + text-align: left; +} + +#Content[layout|="compact"] .PrinterBlock { + flex-direction: row; + padding: 5px 5px 5px 18px; +} + +#Content[layout|="compact"] .ModelCheckBox { + width: 6px; + height: 80%; + left:0; + top:10% +} + +#Content[layout|="compact"] .OneVendorBlock:last-of-type { + margin-bottom: 0px; +} /*-----Notice-----*/ #NoticeMask @@ -148,51 +322,149 @@ img.ModelThumbnail justify-content:flex-end; } + .search { - width: 100%; - position: relative; - display: flex; + position: absolute; + left:66px; + top: 14px; + width: 34px; + height: 34px; + z-index: 99; + overflow: hidden; } - + +.search:focus-within, +.search[hasvalue="1"] { + width: calc(100% - 194px); +} + .searchTerm { width: 100%; - border: 1px solid #DBDBDB; /* ORCA Searchbox > match border style */ - /*border-right: none;*/ - padding: 5px; - padding-left:32px; - height: 20px; /* ORCA match height */ - line-height: 20px; /* ORCA center text vertically */ - border-radius: 5px 5px 5px 5px; + height: 100%; + padding: 4px 5px; + border-radius: 6px; outline: none; - color: #9DBFAF; -} -@media (prefers-color-scheme: dark) { /* ORCA Searchbox > add dark mode support */ - .searchTerm {border: 1px solid #4A4A51;} + box-sizing: border-box; + background: var(--button-bg-normal); + border: 1px solid var(--button-bg-normal); } -.searchTerm:focus{ - color: #363636; /* ORCA Searchbox > use normal text color */ - border-color:#009688; /* ORCA Searchbox > highlight border color when focused. like on normal UI */ -} -@media (prefers-color-scheme: dark) { /* ORCA Searchbox > add dark mode support */ - .searchTerm:focus{color: #FFFFFF} +@media (prefers-reduced-motion: no-preference) { + .searchTerm { + transition: background-color .2s + } } -#search-icon{ /* ORCA */ - position:absolute; - top: 50%; - transform: translateY(-50%); - left:8px; - margin:0px auto; - fill:#7C8282 -} -@media (prefers-color-scheme: dark) { /* ORCA Searchbox > add dark mode support */ - #search-icon{fill:#949494} +.searchTerm, +.search-placeholder { + line-height: 24px; /* ORCA center text vertically */ + font-size: 14px; } -/*Resize the wrap to see the search bar change!*/ -.wrap{ - width: 30%; - padding-bottom: 5px; - padding-left: 32px; /* ORCA Align with content */ +.search:focus-within .searchTerm, +.search[hasvalue="1"] .searchTerm { + padding-left:33px; + background: var(--bg-color); + border-color: var(--main-color); +} + +.search[hasvalue="1"]:not(:focus-within, :hover) .searchTerm { + border-color: var(--border-color); +} + +.search:not(:focus-within, [hasvalue="1"]) .searchTerm { + cursor: default; +} + +.search:not(:focus-within, [hasvalue="1"]) .searchTerm:hover { + background: var(--button-bg-hover); +} + +.search-placeholder { + color: var(--fg-color-disabled); + left: 33px; +} + +.searchTerm:not(:placeholder-shown) + .search-placeholder { + opacity: 0; +} + +.search-icon, +.search-placeholder { + position: absolute; + top: 50%; + transform: translateY(-50%); + pointer-events: none; +} + +.search-icon { + left: 9px; + --icon-url: var(--icon-search); +} + +.SidebarBtn { + position: absolute; + left: 20px; + top: 14px; + padding: 9px; + border-radius: 6px; +} + +.SidebarBtn .icon16 { + --icon-url: var(--icon-sidebar); +} + +#SidebarContainer { + position: absolute; + top: 0; + left: -240px; + right: 0; + height: 100%; + z-index: 999999; + display: flex; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + #SidebarContainer { + transition: background-color .2s, left .2s + } +} + +#SidebarContainer[open="1"] { + left: 0px; + pointer-events: all; + background: rgba(0,0,0,.3); +} + +#Sidebar { + flex: 0 0 220px; + background: var(--bg-color); + box-shadow: 5px 0 20px rgba(0,0,0,.2); + padding: 15px 0; + overflow-y: auto; +} + +#Sidebar .title { + font-size: 17px; + line-height: 17px; + font-weight: 600; + padding: 0 0 5px 20px; +} + +#Sidebar .SidebarItem { + width: 100%; + padding: 2px 10px 2px 20px; + color:var(--fg-color-text); + font-size: 14px; + border: 1px solid transparent; + box-sizing: border-box; +} + +#Sidebar .SidebarItem:hover { + border-color: var(--main-color); +} + +#SidebarContainer .back { + flex: 1; } diff --git a/resources/web/guide/21/21.js b/resources/web/guide/21/21.js index 53cef68b7e..5ad3a8b219 100644 --- a/resources/web/guide/21/21.js +++ b/resources/web/guide/21/21.js @@ -67,6 +67,13 @@ function HandleModelList( pVal ) return; pModel=pVal['model']; + + // ORCA ensure list correctly ordered + pModel = pModel.sort((a, b)=>(a["vendor"].localeCompare(b["vendor"]))) + pModel = [ // move custom printers to top + ...pModel.filter(i=>i.vendor === "Custom"), + ...pModel.filter(i=>i.vendor !== "Custom") + ]; let nTotal=pModel.length; let ModelHtml={}; @@ -89,11 +96,15 @@ function HandleModelList( pVal ) let HtmlNewVendor='

      '+ '
      '+ -' '+sVV+''+ -'
      '+ -'
      all
      '+ -'
      none
      '+ -'
      '+ +' '+sVV+''+ +'
      '+ +'
      ' + +' '+ +'
      '+ +//'
      '+ +//'
      all
      '+ +//'
      none
      '+ +//'
      '+ '
      '+ '
      '+ '
      '+ @@ -130,6 +141,14 @@ function HandleModelList( pVal ) } } + const $SidebarVendors = $('#SidebarVendors'); + let SidebarHTML = ""; + $(`.OneVendorBlock`).each((i, el)=>{ + UpdateVendorCheckbox(el.getAttribute("vendor")); + SidebarHTML +=`
      ${el.getAttribute('vendor')}
      `; + }); + $SidebarVendors.html(SidebarHTML) + // let AlreadySelect=$(".ModelCheckBoxSelected"); // let nSelect=AlreadySelect.length; // if(nSelect==0) @@ -140,6 +159,14 @@ function HandleModelList( pVal ) TranslatePage(); } +function scrollToVendor(vendor) { + const el = $(".OneVendorBlock[vendor='"+vendor+"']")[0]; + if (el){ + document.getElementById('SidebarContainer').setAttribute('open', '0'); + document.getElementById('Content').scrollTo({top: el.offsetTop, behavior: "smooth"}); + } +} + function SetModelSelect(vendor, model, checked) { if (!ModelNozzleSelected.hasOwnProperty(vendor) && !checked) { return; @@ -153,6 +180,8 @@ function SetModelSelect(vendor, model, checked) { if (oVendor.hasOwnProperty(model) || checked) { oVendor[model] = checked; } + + UpdateVendorCheckbox(vendor) } function GetModelSelect(vendor, model) { @@ -182,6 +211,8 @@ function FilterModelList(keyword) { SetModelSelect(strVendor, strModel, $(OneItem).hasClass('ModelCheckBoxSelected')); } + $('.search')[0].setAttribute("hasvalue", keyword ? "1" : "0") + let nTotal = pModel.length; let ModelHtml = {}; let kwSplit = keyword.toLowerCase().match(/\S+/g) || []; @@ -209,10 +240,14 @@ function FilterModelList(keyword) { let HtmlNewVendor = '
      ' + '
      ' + ' ' + sVV + '' + - '
      ' + - '
      all
      ' + - '
      none
      ' + - '
      ' + + '
      '+ + '
      ' + + ' '+ + '
      '+ + //'
      ' + + //'
      all
      ' + + //'
      none
      ' + + //'
      ' + '
      ' + '
      ' + '
      ' + @@ -252,6 +287,17 @@ function FilterModelList(keyword) { $(OneItem).removeClass('ModelCheckBoxSelected'); } + const $SidebarVendors = $('#SidebarVendors'); + let SidebarHTML = ""; + $(`.OneVendorBlock`).each((i, el)=>{ + UpdateVendorCheckbox(el.getAttribute("vendor")); + SidebarHTML +=`
      ${el.getAttribute('vendor')}
      `; + }); + $SidebarVendors.html(SidebarHTML) + + const $content = $('#Content'); + $content.css("padding-right", $content[0].scrollHeight > $content[0].clientHeight ? "10px" : "20px"); + // let AlreadySelect=$(".ModelCheckBoxSelected"); // let nSelect=AlreadySelect.length; // if(nSelect==0) @@ -287,9 +333,16 @@ function CreatePrinterBlock(OneModel) '
      '+ ''+ '
      '+ + '
      ?
      '+ + '
      '+ + //'
      Print volume
      '+ + //'
      ' + OneModel['printable_height'] + '
      '+ + '
      Nozzle
      '+ + '
      ' + OneModel['nozzle_diameter'].replaceAll(";", " · ") + '
      '+ + '
      '+ '
      '+ '
      '+ - '

      '+ vendorName +'

      ' + modelName +'

      '+ + '
      '+ modelName +'
      '+ // >

      '+ vendorName +'

      '
      '+ '
      '; } @@ -313,6 +366,29 @@ function SelectPrinterNone( sVendor ) }); } +function ChooseVendor(sVendor) { + const $cbs = $(`.OneVendorBlock[vendor='${sVendor}'] .ModelCheckBox`); + const sel = $cbs.length && $cbs.not('.ModelCheckBoxSelected').length; + + sel ? $cbs.addClass('ModelCheckBoxSelected') + : $cbs.removeClass('ModelCheckBoxSelected'); + + $cbs.each((i, el)=>{SetModelSelect(sVendor, el.getAttribute('model'), sel)}); +} + +function UpdateVendorCheckbox(sVendor) { + const $vb = $(`.OneVendorBlock[vendor='${sVendor}']`); + const $cbs = $vb.find(`.ModelCheckBox`); + const $vcb = $vb.find(`.VendorCheckbox`); + + const selCount = $cbs.filter('.ModelCheckBoxSelected').length; + const allSel = selCount === $cbs.length && selCount > 0; + const nonSel = selCount === 0; + + $vcb.prop({checked: allSel , indeterminate: !allSel && !nonSel}); + + $vb.find(".modelCount").text(selCount + " / " + $cbs.length); +} function GotoFilamentPage() { diff --git a/resources/web/guide/21/index.html b/resources/web/guide/21/index.html index 6a929c9eec..a0fe7d0072 100644 --- a/resources/web/guide/21/index.html +++ b/resources/web/guide/21/index.html @@ -20,16 +20,34 @@
      Printer Selection
      -
      -