Merge branch 'main' into feat/configurable-bambu-network-lib
This commit is contained in:
@@ -35,6 +35,11 @@ Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const Container& in)
|
||||
return out;
|
||||
}
|
||||
|
||||
Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Polylines& in)
|
||||
{
|
||||
return Slic3rPoints_to_Paths64(in);
|
||||
}
|
||||
|
||||
Points Path64ToPoints(const Clipper2Lib::Path64& path64)
|
||||
{
|
||||
Points points;
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
#include "clipper2/clipper.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Slic3r::Polylines& in);
|
||||
Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in);
|
||||
Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
|
||||
Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
|
||||
ExPolygons union_ex_2(const Polygons &expolygons);
|
||||
|
||||
@@ -200,6 +200,10 @@ void Fill3DHoneycomb::_fill_surface_single(
|
||||
if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle);
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
|
||||
// Expand the bounding box to avoid artifacts at the edges
|
||||
coord_t expand = 5 * (scale_(this->spacing));
|
||||
bb.offset(expand);
|
||||
|
||||
// Note: with equally-scaled X/Y/Z, the pattern will create a vertically-stretched
|
||||
// truncated octahedron; so Z is pre-adjusted first by scaling by sqrt(2)
|
||||
coordf_t zScale = sqrt(2);
|
||||
|
||||
@@ -1371,42 +1371,47 @@ void Filler::_fill_surface_single(
|
||||
all_polylines.reserve(lines.size());
|
||||
std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; });
|
||||
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(all_polylines, params, spacing);
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(all_polylines, params, spacing);
|
||||
|
||||
// Crop all polylines
|
||||
all_polylines = intersection_pl(std::move(all_polylines), expolygon);
|
||||
#endif
|
||||
}
|
||||
|
||||
// After intersection_pl some polylines with only one line are split into more lines
|
||||
for (Polyline &polyline : all_polylines) {
|
||||
//FIXME assert that all the points are collinear and in between the start and end point.
|
||||
if (polyline.points.size() > 2)
|
||||
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
|
||||
}
|
||||
// assert(has_no_collinear_lines(all_polylines));
|
||||
if (params.multiline == 1) {
|
||||
// After intersection_pl some polylines with only one line are split into more lines
|
||||
for (Polyline& polyline : all_polylines) {
|
||||
// FIXME assert that all the points are collinear and in between the start and end point.
|
||||
if (polyline.points.size() > 2)
|
||||
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
|
||||
}
|
||||
// assert(has_no_collinear_lines(all_polylines));
|
||||
|
||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_infill_lines_to_svg(expolygon, all_polylines, debug_out_path("FillAdaptive-initial-%d.svg", iRun++));
|
||||
}
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_infill_lines_to_svg(expolygon, all_polylines, debug_out_path("FillAdaptive-initial-%d.svg", iRun++));
|
||||
}
|
||||
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
|
||||
|
||||
const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
|
||||
const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
|
||||
const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
|
||||
const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
|
||||
|
||||
Polylines all_polylines_with_hooks = all_polylines.size() > 1 ? connect_lines_using_hooks(std::move(all_polylines), expolygon, this->spacing, hook_length, hook_length_max) : std::move(all_polylines);
|
||||
|
||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_infill_lines_to_svg(expolygon, all_polylines_with_hooks, debug_out_path("FillAdaptive-hooks-%d.svg", iRun++));
|
||||
}
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_infill_lines_to_svg(expolygon, all_polylines_with_hooks, debug_out_path("FillAdaptive-hooks-%d.svg", iRun++));
|
||||
}
|
||||
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
|
||||
|
||||
chain_or_connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params);
|
||||
chain_or_connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params);
|
||||
} else {
|
||||
// if multiline is > 1 infill is ready to connect
|
||||
chain_or_connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);
|
||||
}
|
||||
|
||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
||||
{
|
||||
@@ -1443,6 +1448,17 @@ static std::vector<CubeProperties> make_cubes_properties(double max_cube_edge_le
|
||||
if (edge_length > max_cube_edge_length)
|
||||
break;
|
||||
}
|
||||
// Orca: Ensure at least 2 levels so build_octree() will insert triangles.
|
||||
// Fixes scenario where adaptive fill is disconnected from walls on low densities
|
||||
if (cubes_properties.size() == 1) {
|
||||
CubeProperties p = cubes_properties.back();
|
||||
p.edge_length *= 2.0;
|
||||
p.height = p.edge_length * sqrt(3);
|
||||
p.diagonal_length = p.edge_length * sqrt(2);
|
||||
p.line_z_distance = p.edge_length / sqrt(3);
|
||||
p.line_xy_distance = p.edge_length / sqrt(6);
|
||||
cubes_properties.push_back(p);
|
||||
}
|
||||
return cubes_properties;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Clipper2Utils.hpp"
|
||||
#include "../EdgeGrid.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Geometry/Circle.hpp"
|
||||
@@ -2699,60 +2700,77 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const Polygons &boun
|
||||
connect_base_support(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
|
||||
}
|
||||
|
||||
//Fill Multiline
|
||||
// Fill Multiline -Clipper2 version
|
||||
void multiline_fill(Polylines& polylines, const FillParams& params, float spacing)
|
||||
{
|
||||
if (params.multiline > 1) {
|
||||
const int n_lines = params.multiline;
|
||||
const int n_polylines = static_cast<int>(polylines.size());
|
||||
Polylines all_polylines;
|
||||
all_polylines.reserve(n_lines * n_polylines);
|
||||
if (params.multiline <= 1)
|
||||
return;
|
||||
|
||||
const float center = (n_lines - 1) / 2.0f;
|
||||
const int n_lines = params.multiline;
|
||||
const int n_polylines = static_cast<int>(polylines.size());
|
||||
Polylines all_polylines;
|
||||
all_polylines.reserve(n_lines * n_polylines);
|
||||
|
||||
for (int line = 0; line < n_lines; ++line) {
|
||||
float offset = scale_((static_cast<float>(line) - center) * spacing);
|
||||
// Remove invalid polylines
|
||||
polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
|
||||
[](const Polyline& p) { return p.size() < 2; }),
|
||||
polylines.end());
|
||||
|
||||
for (const Polyline& pl : polylines) {
|
||||
const size_t n = pl.points.size();
|
||||
if (n < 2) {
|
||||
all_polylines.emplace_back(pl);
|
||||
continue;
|
||||
}
|
||||
if (polylines.empty())
|
||||
return;
|
||||
// Convert source polylines to Clipper2 paths
|
||||
Clipper2Lib::Paths64 subject_paths = Slic3rPolylines_to_Paths64(polylines);
|
||||
|
||||
Points new_points;
|
||||
new_points.reserve(n);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Vec2f tangent;
|
||||
// For the first and last point, if the polyline is a
|
||||
// closed loop, get the tangent from the points on either
|
||||
// side of the join, otherwise just use the first or last
|
||||
// line.
|
||||
if (i == 0) {
|
||||
if (pl.points[0] == pl.points[n-1]) {
|
||||
tangent = (pl.points[1] - pl.points[n-2]).template cast<float>().normalized();
|
||||
} else {
|
||||
tangent = (pl.points[1] - pl.points[0]).template cast<float>().normalized();
|
||||
}
|
||||
} else if (i == n - 1) {
|
||||
if (pl.points[0] == pl.points[n-1]) {
|
||||
tangent = (pl.points[1] - pl.points[n-2]).template cast<float>().normalized();
|
||||
} else {
|
||||
tangent = (pl.points[n-1] - pl.points[n-2]).template cast<float>().normalized();
|
||||
}
|
||||
} else
|
||||
tangent = (pl.points[i+1] - pl.points[i-1]).template cast<float>().normalized();
|
||||
Vec2f normal(-tangent.y(), tangent.x());
|
||||
const double miter_limit = 2.0;
|
||||
const int rings = n_lines / 2;
|
||||
|
||||
Point p = pl.points[i] + (normal * offset).template cast<coord_t>();
|
||||
new_points.push_back(p);
|
||||
}
|
||||
// Compute offsets (in units of spacing)
|
||||
std::vector<double> offsets;
|
||||
offsets.reserve(n_lines);
|
||||
|
||||
all_polylines.emplace_back(std::move(new_points));
|
||||
}
|
||||
}
|
||||
polylines = std::move(all_polylines);
|
||||
if (n_lines % 2 != 0) {
|
||||
// Odd: center line at offset = 0
|
||||
offsets.push_back(0.0);
|
||||
|
||||
for (int i = 1; i <= rings; ++i)
|
||||
offsets.push_back(i * spacing);
|
||||
} else {
|
||||
// Even: no center, start at 0.5 * spacing
|
||||
double start = 0.5 * spacing;
|
||||
for (int i = 0; i < rings; ++i)
|
||||
offsets.push_back(start + i * spacing);
|
||||
}
|
||||
|
||||
// Process each offset
|
||||
Clipper2Lib::ClipperOffset offsetter(miter_limit);
|
||||
offsetter.AddPaths(subject_paths, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Round);
|
||||
|
||||
for (double t : offsets) {
|
||||
if (t == 0.0) {
|
||||
// Center line (only applies when n_lines is odd)
|
||||
all_polylines.insert(all_polylines.end(), polylines.begin(), polylines.end());
|
||||
continue;
|
||||
}
|
||||
|
||||
// ClipperOffset with current offset distance (union is not needed here)
|
||||
Clipper2Lib::Paths64 offset_paths;
|
||||
offsetter.Execute(scale_(t), offset_paths);
|
||||
if (offset_paths.empty())
|
||||
continue;
|
||||
|
||||
// Convert back to polylines
|
||||
Polylines new_polylines = Paths64_to_polylines(offset_paths);
|
||||
|
||||
for (Polyline& pl : new_polylines) {
|
||||
if (pl.points.size() < 3)
|
||||
continue;
|
||||
if (pl.points.front() != pl.points.back())
|
||||
pl.points.push_back(pl.points.front());
|
||||
all_polylines.emplace_back(std::move(pl));
|
||||
}
|
||||
}
|
||||
|
||||
polylines = std::move(all_polylines);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -19,7 +19,7 @@ void FillConcentric::_fill_surface_single(
|
||||
// no rotation is supported for this infill pattern
|
||||
BoundingBox bounding_box = expolygon.contour.bounding_box();
|
||||
|
||||
coord_t min_spacing = scale_(this->spacing);
|
||||
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
||||
coord_t distance = coord_t(min_spacing / params.density);
|
||||
|
||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||
@@ -27,8 +27,12 @@ void FillConcentric::_fill_surface_single(
|
||||
this->spacing = unscale<double>(distance);
|
||||
}
|
||||
|
||||
Polygons loops = to_polygons(expolygon);
|
||||
ExPolygons last { std::move(expolygon) };
|
||||
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
|
||||
ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * (params.multiline - 1) * this->spacing )));
|
||||
|
||||
Polygons loops = to_polygons(contracted);
|
||||
|
||||
ExPolygons last { std::move(contracted) };
|
||||
while (! last.empty()) {
|
||||
last = offset2_ex(last, -(distance + min_spacing/2), +min_spacing/2);
|
||||
append(loops, to_polygons(last));
|
||||
@@ -46,6 +50,9 @@ void FillConcentric::_fill_surface_single(
|
||||
last_pos = polylines_out.back().last_point();
|
||||
}
|
||||
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(polylines_out, params, spacing);
|
||||
|
||||
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
|
||||
// Keep valid paths only.
|
||||
size_t j = iPathFirst;
|
||||
|
||||
@@ -74,7 +74,7 @@ void FillHoneycomb::_fill_surface_single(
|
||||
}
|
||||
}
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(all_polylines, params, 1.1 * spacing);
|
||||
multiline_fill(all_polylines, params, spacing);
|
||||
|
||||
all_polylines = intersection_pl(std::move(all_polylines), expolygon);
|
||||
chain_or_connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);
|
||||
|
||||
@@ -81,6 +81,9 @@ void FillPlanePath::_fill_surface_single(
|
||||
|
||||
BoundingBox snug_bounding_box = get_extents(expolygon).inflated(SCALED_EPSILON);
|
||||
|
||||
// Expand the bounding box to avoid artifacts at the edges
|
||||
snug_bounding_box.offset(scale_(this->spacing)*params.multiline);
|
||||
|
||||
// Rotated bounding box of the area to fill in with the pattern.
|
||||
BoundingBox bounding_box = align ?
|
||||
// Sparse infill needs to be aligned across layers. Align infill across layers using the object's bounding box.
|
||||
@@ -97,7 +100,7 @@ void FillPlanePath::_fill_surface_single(
|
||||
|
||||
Polyline polyline;
|
||||
{
|
||||
auto distance_between_lines = scaled<double>(this->spacing) / params.density;
|
||||
auto distance_between_lines = scaled<double>(this->spacing) * params.multiline / params.density;
|
||||
auto min_x = coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines));
|
||||
auto min_y = coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines));
|
||||
auto max_x = coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines));
|
||||
@@ -117,8 +120,13 @@ void FillPlanePath::_fill_surface_single(
|
||||
}
|
||||
}
|
||||
|
||||
Polylines polylines = {polyline};
|
||||
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(polylines, params, spacing);
|
||||
|
||||
if (polyline.size() >= 2) {
|
||||
Polylines polylines = intersection_pl(polyline, expolygon);
|
||||
polylines = intersection_pl(std::move(polylines), expolygon);
|
||||
if (!polylines.empty()) {
|
||||
Polylines chained;
|
||||
if (params.dont_connect() || params.density > 0.5) {
|
||||
|
||||
@@ -3000,7 +3000,7 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
|
||||
params.density /= double(sweep_params.size());
|
||||
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||
|
||||
ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap - 0.5 * this->spacing)));
|
||||
ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap + 0.5 * params.multiline * this->spacing)));//increase offset to crop infill lines when using multiline infill
|
||||
if (poly_with_offset_base.n_contours == 0)
|
||||
// Not a single infill line fits.
|
||||
return true;
|
||||
@@ -3012,19 +3012,24 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
|
||||
for (const SweepParams &sweep : sweep_params) {
|
||||
// Rotate polygons so that we can work with vertical lines here
|
||||
float angle = rotate_vector.first + sweep.angle_base;
|
||||
//Fill Multiline
|
||||
for (int i = 0; i < params.multiline; ++i) {
|
||||
coord_t group_offset = i * line_spacing;
|
||||
coord_t internal_offset = (i - (params.multiline - 1) / 2.0f) * line_width;
|
||||
coord_t total_offset = group_offset + internal_offset;
|
||||
coord_t pattern_shift = scale_(sweep.pattern_shift + unscale_(total_offset));
|
||||
|
||||
make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, -angle), rotate_vector.second.rotated(-angle), angle,
|
||||
line_width + coord_t(SCALED_EPSILON), line_spacing, pattern_shift, fill_lines);
|
||||
}
|
||||
make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, -angle), rotate_vector.second.rotated(-angle), angle,
|
||||
line_width + coord_t(SCALED_EPSILON), line_spacing, coord_t(scale_(sweep.pattern_shift)), fill_lines);
|
||||
}
|
||||
|
||||
// Apply multiline offset if needed
|
||||
multiline_fill(fill_lines, params, spacing);
|
||||
|
||||
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
|
||||
ExPolygons contracted = offset_ex(surface->expolygon, -float(scale_(0.5 * this->spacing)));
|
||||
|
||||
// if contraction results in empty polygon, use original surface
|
||||
const ExPolygon &intersection_surface = contracted.empty() ? surface->expolygon : contracted.front();
|
||||
|
||||
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb ) && params.multiline >1 )
|
||||
// Intersect polylines with perimeter
|
||||
fill_lines = intersection_pl(std::move(fill_lines), intersection_surface);
|
||||
|
||||
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb ) && params.multiline >1 )
|
||||
remove_overlapped(fill_lines, line_width);
|
||||
|
||||
if (!fill_lines.empty()) {
|
||||
@@ -3033,7 +3038,260 @@ if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb
|
||||
fill_lines = chain_polylines(std::move(fill_lines));
|
||||
append(polylines_out, std::move(fill_lines));
|
||||
} else
|
||||
connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->spacing, params);
|
||||
connect_infill(std::move(fill_lines), intersection_surface, polylines_out, this->spacing, params);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillRectilinear::fill_surface_trapezoidal(
|
||||
const Surface* surface,
|
||||
FillParams params,
|
||||
const std::initializer_list<SweepParams>& sweep_params,
|
||||
Polylines& polylines_out,
|
||||
int Pattern_type) // 0=grid, 1=triangular
|
||||
{
|
||||
assert(params.multiline > 1);
|
||||
|
||||
Polylines polylines;
|
||||
|
||||
// Common parameters
|
||||
const coord_t d1 = coord_t(scale_(this->spacing)) * params.multiline; // Infill total wall thickness
|
||||
|
||||
// Pattern-specific parameters
|
||||
coord_t period;
|
||||
double base_angle;
|
||||
std::pair<double, Point> rotate_vector = this->_infill_direction(surface);
|
||||
|
||||
if (Pattern_type == 0) {
|
||||
// Grid pattern parameters
|
||||
period = coord_t((2.0 * d1 / params.density) * std::sqrt(2.0));
|
||||
base_angle = rotate_vector.first + M_PI_4; // 45
|
||||
} else {
|
||||
// Triangular pattern parameters
|
||||
period = coord_t(( 2.0 * d1 / params.density) * std::sqrt(3.0));
|
||||
base_angle = rotate_vector.first + M_PI_2; //90
|
||||
}
|
||||
|
||||
// Obtain the expolygon and rotate to align with pattern base angle
|
||||
ExPolygon expolygon = surface->expolygon;
|
||||
if (std::abs(base_angle) >= EPSILON) {
|
||||
expolygon.rotate(-base_angle, rotate_vector.second);
|
||||
}
|
||||
|
||||
// Use extended object bounding box for consistent pattern across layers
|
||||
BoundingBox bb = this->extended_object_bounding_box();
|
||||
|
||||
switch (Pattern_type) {
|
||||
case 0: // Grid / Trapezoidal
|
||||
{
|
||||
// Generate a non-crossing trapezoidal pattern to avoid overextrusion at intersections when `multiline > 1`.
|
||||
// P1--P2
|
||||
// / \
|
||||
// P0/ \P3__P4
|
||||
//
|
||||
// P1x-P2x=P3x-P4x=d1
|
||||
// P0y-P1y=P2y-P3y=d2
|
||||
|
||||
const coord_t d2 = coord_t(0.5 * period - d1);
|
||||
|
||||
// Align bounding box to the grid
|
||||
bb.merge(align_to_grid(bb.min, Point(period, period)));
|
||||
const coord_t xmin = bb.min.x();
|
||||
const coord_t xmax = bb.max.x();
|
||||
const coord_t ymin = bb.min.y();
|
||||
const coord_t ymax = bb.max.y();
|
||||
|
||||
// Create the two base row patterns once
|
||||
Polyline base_row_normal;
|
||||
base_row_normal.points.reserve(((xmax - xmin) / period + 1) * 5); // 5 points per trapezoid
|
||||
Polyline base_row_flipped;
|
||||
base_row_flipped.points.reserve(((xmax - xmin) / period + 1) * 5); // 5 points per trapezoid
|
||||
|
||||
// Build complete rows from xmin to xmax
|
||||
for (coord_t x = xmin; x < xmax; x += period) {
|
||||
// Normal row
|
||||
base_row_normal.points.emplace_back(Point(x, d1 / 2)); // P0
|
||||
base_row_normal.points.emplace_back(Point(x + d1, d1 / 2)); // P1
|
||||
base_row_normal.points.emplace_back(Point(x + d1 + d2, d1 / 2 + d2)); // P2
|
||||
base_row_normal.points.emplace_back(Point(x + 2 * d1 + d2, d1 / 2 + d2)); // P3
|
||||
base_row_normal.points.emplace_back(Point(x + 2 * d1 + 2 * d2, d1 / 2)); // P4
|
||||
}
|
||||
|
||||
// Flipped row (mirrored vertically)
|
||||
base_row_flipped.points = base_row_normal.points;
|
||||
for (auto& p : base_row_flipped.points) {
|
||||
p.y() = period / 2 - p.y();
|
||||
}
|
||||
|
||||
// Pre-allocate polylines
|
||||
const size_t estimated_rows = ((ymax - ymin) / (period / 2) + 1);
|
||||
polylines.reserve(estimated_rows);
|
||||
|
||||
bool flip_vertical = false;
|
||||
|
||||
// Now just copy and translate vertically
|
||||
for (coord_t y = ymin; y < ymax; y += period / 2) {
|
||||
Polyline pl_row = flip_vertical ? base_row_flipped : base_row_normal;
|
||||
|
||||
// Translate all points vertically
|
||||
for (Point& p : pl_row.points) {
|
||||
p.y() += y;
|
||||
}
|
||||
|
||||
polylines.emplace_back(std::move(pl_row));
|
||||
flip_vertical = !flip_vertical;
|
||||
}
|
||||
|
||||
// transpose points for odd layers
|
||||
if (layer_id % 2 == 1) {
|
||||
for (Polyline& pl : polylines) {
|
||||
for (Point& p : pl.points) {
|
||||
std::swap(p.x(), p.y());
|
||||
p.x() += d1 / 2;
|
||||
p.y() -= d1 / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // Triangular
|
||||
{
|
||||
// Generate a non-crossing trapezoidal pattern with a base line below.
|
||||
// P1-P2
|
||||
// / \
|
||||
// P0/ \P3_P4
|
||||
// ----------------
|
||||
// P1x-P2x=P3x-P4x=d2
|
||||
// P0y-P1y=P2y-P3y=h-2d1
|
||||
//
|
||||
|
||||
// Triangular pattern density adjustment:
|
||||
const coord_t d2_tri = coord_t(2.0 / std::sqrt(3.0) * d1);
|
||||
const coord_t h = coord_t(0.5 * std::sqrt(3.0) * period); // height of triangle
|
||||
|
||||
// Align bounding box to the grid
|
||||
bb.merge(align_to_grid(bb.center(), Point(period,h)));
|
||||
const int layer_mod = layer_id % 3;
|
||||
const double angle = layer_mod * 2.0 * M_PI / 3.0;
|
||||
|
||||
const Point rotation_center = bb.center();
|
||||
const coord_t half_w = bb.size().x() / 2;
|
||||
const coord_t half_h = bb.size().y() / 2;
|
||||
|
||||
// Compute how many full periods fit in each direction
|
||||
const coord_t num_periods_x = coord_t(std::ceil(half_w / double(period)));
|
||||
coord_t num_periods_y =coord_t(std::ceil(half_h / double(h)));
|
||||
// Ensure an even number of rows so the pattern stays centered
|
||||
if ((num_periods_y % 2) != 0)
|
||||
++num_periods_y;
|
||||
|
||||
// Compute aligned limits (symmetric around the origin)
|
||||
const coord_t x_min_aligned = -num_periods_x * period;
|
||||
const coord_t x_max_aligned = num_periods_x * period;
|
||||
const coord_t y_min_aligned = -num_periods_y * h;
|
||||
const coord_t y_max_aligned = num_periods_y * h;
|
||||
|
||||
// Pre-allocate estimated number of polylines
|
||||
const size_t estimated_rows = (y_max_aligned - y_min_aligned) / h + 2;
|
||||
const size_t estimated_polylines = (estimated_rows + 1) * 2; // base line + trapezoid line per row
|
||||
polylines.reserve(estimated_polylines);
|
||||
|
||||
// Create the two base row templates once
|
||||
Polyline base_line_template;
|
||||
base_line_template.points.reserve(2); // 2 points for base line
|
||||
Polyline trapezoid_row_normal;
|
||||
trapezoid_row_normal.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 5); // 5 points per trapezoid
|
||||
Polyline trapezoid_row_shifted;
|
||||
trapezoid_row_shifted.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 5); // 5 points per trapezoid
|
||||
// Build base line template (from x_min_aligned to x_max_aligned)
|
||||
base_line_template.points.emplace_back(Point(x_min_aligned, 0));
|
||||
base_line_template.points.emplace_back(Point(x_max_aligned, 0));
|
||||
|
||||
// Build complete trapezoid rows once
|
||||
// Normal row (no shift)
|
||||
for (coord_t x = x_min_aligned; x < x_max_aligned; x += period) {
|
||||
trapezoid_row_normal.points.emplace_back(Point(x + d2_tri / 2, d1)); // P0
|
||||
trapezoid_row_normal.points.emplace_back(Point(x + period / 2 - d2_tri / 2, h - d1)); // P1
|
||||
trapezoid_row_normal.points.emplace_back(Point(x + period / 2 + d2_tri / 2, h - d1)); // P2
|
||||
trapezoid_row_normal.points.emplace_back(Point(x + period - d2_tri / 2, d1)); // P3
|
||||
trapezoid_row_normal.points.emplace_back(Point(x + period, d1)); // P4
|
||||
}
|
||||
|
||||
// Shifted row (mirrored vertically)
|
||||
trapezoid_row_shifted.points = trapezoid_row_normal.points;
|
||||
for (auto& p : trapezoid_row_shifted.points)
|
||||
p.y() = h - p.y();
|
||||
|
||||
bool shift_row = false;
|
||||
|
||||
// Generate pattern by copying and translating templates vertically
|
||||
for (coord_t y = y_min_aligned; y < y_max_aligned; y += h) {
|
||||
// Base line - copy and translate
|
||||
Polyline base_line = base_line_template;
|
||||
for (Point& p : base_line.points) {
|
||||
p.y() += y;
|
||||
}
|
||||
polylines.emplace_back(std::move(base_line));
|
||||
|
||||
// Trapezoid line - copy and translate the appropriate template
|
||||
Polyline trapezoid_line = shift_row ? trapezoid_row_shifted : trapezoid_row_normal;
|
||||
for (Point& p : trapezoid_line.points) {
|
||||
p.y() += y;
|
||||
}
|
||||
|
||||
if (!trapezoid_line.points.empty()) {
|
||||
polylines.emplace_back(std::move(trapezoid_line));
|
||||
}
|
||||
|
||||
shift_row = !shift_row;
|
||||
}
|
||||
|
||||
// Rotate around origin (0,0)
|
||||
if (layer_mod)
|
||||
for (auto& pl : polylines)
|
||||
pl.rotate(angle, Point(0,0));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Handle unknown pattern type
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply multiline fill
|
||||
multiline_fill(polylines, params, spacing);
|
||||
|
||||
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
|
||||
ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * this->spacing)));
|
||||
|
||||
// if contraction results in empty polygon, use original surface
|
||||
const ExPolygon &intersection_surface = contracted.empty() ? expolygon : contracted.front();
|
||||
|
||||
// Intersect polylines with offset expolygon
|
||||
polylines = intersection_pl(std::move(polylines), intersection_surface);
|
||||
|
||||
// Remove very short segments that may cause connection issues
|
||||
const double minlength = scale_(0.8 * this->spacing);
|
||||
if (minlength > 0 && !polylines.empty()) {
|
||||
polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
|
||||
[minlength](const Polyline& pl) { return pl.length() < minlength; }),
|
||||
polylines.end());
|
||||
}
|
||||
|
||||
// Connect infill lines using offset expolygon
|
||||
int infill_start_idx = polylines_out.size();
|
||||
if (!polylines.empty()) {
|
||||
Slic3r::Fill::chain_or_connect_infill(std::move(polylines), intersection_surface, polylines_out, this->spacing, params);
|
||||
|
||||
// Rotate back the infill lines to original orientation
|
||||
if (std::abs(base_angle) >= EPSILON) {
|
||||
for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) {
|
||||
it->rotate(base_angle, rotate_vector.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3077,15 +3335,27 @@ Polylines FillMonotonicLine::fill_surface(const Surface* surface, const FillPara
|
||||
Polylines FillGrid::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
{
|
||||
Polylines polylines_out;
|
||||
if (! this->fill_surface_by_multilines(
|
||||
surface, params,
|
||||
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
|
||||
polylines_out))
|
||||
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface() failed to fill a region.";
|
||||
|
||||
if (this->layer_id % 2 == 1)
|
||||
for (int i = 0; i < polylines_out.size(); i++)
|
||||
std::reverse(polylines_out[i].begin(), polylines_out[i].end());
|
||||
if (params.multiline > 1) {
|
||||
// Experimental trapezoidal grid
|
||||
if (!this->fill_surface_trapezoidal(
|
||||
surface, params,
|
||||
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
|
||||
polylines_out,0))
|
||||
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface_trapezoidal() failed.";
|
||||
|
||||
} else {
|
||||
if (!this->fill_surface_by_multilines(
|
||||
surface, params,
|
||||
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
|
||||
polylines_out))
|
||||
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface() failed to fill a region.";
|
||||
|
||||
|
||||
if (this->layer_id % 2 == 1)
|
||||
for (int i = 0; i < polylines_out.size(); i++)
|
||||
std::reverse(polylines_out[i].begin(), polylines_out[i].end());
|
||||
}
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
@@ -3108,12 +3378,23 @@ Polylines FillLateralLattice::fill_surface(const Surface *surface, const FillPar
|
||||
|
||||
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams ¶ms){
|
||||
Polylines polylines_out;
|
||||
if (params.multiline > 1) {
|
||||
// Experimental trapezoidal grid
|
||||
if (!this->fill_surface_trapezoidal(
|
||||
surface, params,
|
||||
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
|
||||
polylines_out,1))
|
||||
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface_trapezoidal() failed.";
|
||||
|
||||
} else {
|
||||
if (! this->fill_surface_by_multilines(
|
||||
surface, params,
|
||||
{ { 0.f, 0.f }, { float(M_PI / 3.), 0.f }, { float(2. * M_PI / 3.), 0. } },
|
||||
polylines_out))
|
||||
BOOST_LOG_TRIVIAL(error) << "FillTriangles::fill_surface() failed to fill a region.";
|
||||
}
|
||||
return polylines_out;
|
||||
|
||||
}
|
||||
|
||||
Polylines FillStars::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
@@ -3144,8 +3425,8 @@ Polylines FillQuarterCubic::fill_surface(const Surface* surface, const FillParam
|
||||
using namespace boost::math::float_constants;
|
||||
Polylines polylines_out;
|
||||
|
||||
coord_t line_width = coord_t(scale_(this->spacing));
|
||||
coord_t period = coord_t(scale_(this->spacing) / params.density) * 4;
|
||||
coord_t line_width = coord_t(scale_(this->spacing)) * params.multiline;
|
||||
coord_t period = coord_t(scale_(this->spacing) *params.multiline / params.density) * 4;
|
||||
|
||||
// First half tetrahedral fill
|
||||
double pattern_z_shift = 0.0;
|
||||
|
||||
@@ -29,6 +29,7 @@ protected:
|
||||
float pattern_shift;
|
||||
};
|
||||
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
|
||||
bool fill_surface_trapezoidal(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out,int Pattern_type);
|
||||
|
||||
// The extended bounding box of the whole object that covers any rotation of every layer.
|
||||
BoundingBox extended_object_bounding_box() const;
|
||||
|
||||
@@ -2727,8 +2727,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
|
||||
auto probe_dist_x = std::max(1., m_config.bed_mesh_probe_distance.value.x());
|
||||
auto probe_dist_y = std::max(1., m_config.bed_mesh_probe_distance.value.y());
|
||||
int probe_count_x = std::max(3, (int) std::ceil(mesh_bbox.size().x() / probe_dist_x));
|
||||
int probe_count_y = std::max(3, (int) std::ceil(mesh_bbox.size().y() / probe_dist_y));
|
||||
int probe_count_x = std::max(3, (int) std::ceil(mesh_bbox.size().x() / probe_dist_x) + 1);
|
||||
int probe_count_y = std::max(3, (int) std::ceil(mesh_bbox.size().y() / probe_dist_y) + 1);
|
||||
auto bed_mesh_algo = "bicubic";
|
||||
if (probe_count_x * probe_count_y <= 6) { // lagrange needs up to a total of 6 mesh points
|
||||
bed_mesh_algo = "lagrange";
|
||||
@@ -6186,10 +6186,16 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
);
|
||||
}
|
||||
|
||||
// if still in avoidance mode and under “max”, clamp to “min”
|
||||
if (m_resonance_avoidance
|
||||
&& speed <= m_config.max_resonance_avoidance_speed.value) {
|
||||
speed = std::min(speed, m_config.min_resonance_avoidance_speed.value);
|
||||
// if still in avoidance mode and under "max", adjust speed:
|
||||
// - speeds in lower half of range: clamp down to "min"
|
||||
// - speeds in upper half of range: boost up to "max"
|
||||
if (m_resonance_avoidance && speed < m_config.max_resonance_avoidance_speed.value) {
|
||||
if (speed < m_config.min_resonance_avoidance_speed.value +
|
||||
((m_config.max_resonance_avoidance_speed.value - m_config.min_resonance_avoidance_speed.value) / 2)) {
|
||||
speed = std::min(speed, m_config.min_resonance_avoidance_speed.value);
|
||||
} else {
|
||||
speed = m_config.max_resonance_avoidance_speed.value;
|
||||
}
|
||||
}
|
||||
|
||||
// reset flag for next segment
|
||||
|
||||
@@ -1045,8 +1045,8 @@ namespace client
|
||||
case coFloatOrPercent:
|
||||
{
|
||||
std::string opt_key(opt.it_range.begin(), opt.it_range.end());
|
||||
if (boost::ends_with(opt_key, "extrusion_width")) {
|
||||
// Extrusion width supports defaults and a complex graph of dependencies.
|
||||
if (boost::ends_with(opt_key, "line_width")) {
|
||||
// Line width supports defaults and a complex graph of dependencies.
|
||||
output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast<unsigned int>(ctx->current_extruder_id)));
|
||||
} else if (! static_cast<const ConfigOptionFloatOrPercent*>(opt.opt)->percent) {
|
||||
// Not a percent, just return the value.
|
||||
@@ -1060,8 +1060,8 @@ namespace client
|
||||
const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over);
|
||||
if (opt_parent == nullptr)
|
||||
ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range);
|
||||
if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) {
|
||||
// Extrusion width supports defaults and a complex graph of dependencies.
|
||||
if (boost::ends_with(opt_def->ratio_over, "line_width")) {
|
||||
// Line width supports defaults and a complex graph of dependencies.
|
||||
assert(opt_parent->type() == coFloatOrPercent);
|
||||
v *= Flow::extrusion_width(opt_def->ratio_over, static_cast<const ConfigOptionFloatOrPercent*>(opt_parent), *ctx, static_cast<unsigned int>(ctx->current_extruder_id));
|
||||
break;
|
||||
@@ -2197,9 +2197,8 @@ namespace client
|
||||
initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_initializer_list, _r1, _a, _b, _1)]
|
||||
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
|
||||
// Only process such variable references, which return a naked vector variable.
|
||||
// Orca todo: following code cause strange build errors with MSVC C++17
|
||||
// | eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >>
|
||||
// variable_reference(_r1)[px::val(qi::_pass) = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)]
|
||||
| eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >>
|
||||
variable_reference(_r1)[qi::_pass = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)]
|
||||
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
|
||||
| conditional_expression(_r1)
|
||||
[px::bind(&MyContext::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)]
|
||||
|
||||
@@ -2751,6 +2751,8 @@ Preset *PresetBundle::get_similar_printer_preset(std::string printer_model, std:
|
||||
{
|
||||
if (printer_model.empty())
|
||||
printer_model = printers.get_selected_preset().config.opt_string("printer_model");
|
||||
if (printer_model.empty()) // ORCA ensure a compatible model exist. fixes switches to blank preset if preset has no inherited value
|
||||
return nullptr;
|
||||
auto printer_variant_old = printers.get_selected_preset().config.opt_string("printer_variant");
|
||||
std::map<std::string, Preset*> printer_presets;
|
||||
for (auto &preset : printers.m_presets) {
|
||||
@@ -2761,7 +2763,8 @@ Preset *PresetBundle::get_similar_printer_preset(std::string printer_model, std:
|
||||
}
|
||||
if (printer_presets.empty())
|
||||
return nullptr;
|
||||
auto prefer_printer = printers.get_selected_preset().name;
|
||||
auto prefer_printer = printers.get_selected_preset().alias; //.name ORCA use alias instead "name" for calling system presets. otherwise nozzle combo will not change printer presets if they custom named
|
||||
|
||||
if (!printer_variant.empty())
|
||||
boost::replace_all(prefer_printer, printer_variant_old, printer_variant);
|
||||
else if (auto n = prefer_printer.find(printer_variant_old); n != std::string::npos)
|
||||
|
||||
@@ -2733,7 +2733,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Fill Multiline");
|
||||
def->tooltip = L("Using multiple lines for the infill pattern, if supported by infill pattern.");
|
||||
def->min = 1;
|
||||
def->max = 5; // Maximum number of lines for infill pattern
|
||||
def->max = 10; // Maximum number of lines for infill pattern
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("sparse_infill_pattern", coEnum);
|
||||
@@ -7646,6 +7646,9 @@ std::set<std::string> filament_options_with_variant = {
|
||||
"filament_retraction_length",
|
||||
"filament_z_hop",
|
||||
"filament_z_hop_types",
|
||||
"filament_retract_lift_above",
|
||||
"filament_retract_lift_below",
|
||||
"filament_retract_lift_enforce",
|
||||
"filament_retract_restart_extra",
|
||||
"filament_retraction_speed",
|
||||
"filament_deretraction_speed",
|
||||
@@ -7664,7 +7667,11 @@ std::set<std::string> filament_options_with_variant = {
|
||||
"filament_flush_volumetric_speed",
|
||||
"filament_flush_temp",
|
||||
"volumetric_speed_coefficients",
|
||||
"filament_adaptive_volumetric_speed"
|
||||
"filament_adaptive_volumetric_speed",
|
||||
"filament_ironing_flow",
|
||||
"filament_ironing_spacing",
|
||||
"filament_ironing_inset",
|
||||
"filament_ironing_speed"
|
||||
};
|
||||
|
||||
// Parameters that are the same as the number of extruders
|
||||
|
||||
@@ -604,8 +604,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
|
||||
// Infill patterns that support multiline infill.
|
||||
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
|
||||
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb ||
|
||||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic;
|
||||
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric ||
|
||||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral;
|
||||
|
||||
// If there is infill, enable/disable fill_multiline according to whether the pattern supports multiline infill.
|
||||
if (have_infill) {
|
||||
@@ -774,10 +774,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
// Orca: Force solid support interface when using support ironing
|
||||
toggle_field("support_interface_spacing", have_support_material && have_support_interface && !has_support_ironing);
|
||||
|
||||
bool have_skirt_height = have_skirt &&
|
||||
(config->opt_int("skirt_height") > 1 || config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
|
||||
toggle_line("support_speed", have_support_material || have_skirt_height);
|
||||
toggle_line("support_interface_speed", have_support_material && have_support_interface);
|
||||
// see issue #10915
|
||||
// bool have_skirt_height = have_skirt &&
|
||||
// (config->opt_int("skirt_height") > 1 || config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
|
||||
// toggle_line("support_speed", have_support_material || have_skirt_height);
|
||||
// toggle_line("support_interface_speed", have_support_material && have_support_interface);
|
||||
|
||||
// BBS
|
||||
//toggle_field("support_material_synchronize_layers", have_support_soluble);
|
||||
@@ -934,12 +935,15 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
bool lattice_options = config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ipLateralLattice;
|
||||
for (auto el : { "lateral_lattice_angle_1", "lateral_lattice_angle_2"})
|
||||
toggle_line(el, lattice_options);
|
||||
|
||||
// Adaptative Cubic and support cubic infill patterns do not support infill rotation.
|
||||
bool FillAdaptive = (pattern == InfillPattern::ipAdaptiveCubic || pattern == InfillPattern::ipSupportCubic);
|
||||
|
||||
//Orca: disable infill_direction/solid_infill_direction if sparse_infill_rotate_template/solid_infill_rotate_template is not empty value
|
||||
toggle_field("infill_direction", config->opt_string("sparse_infill_rotate_template") == "");
|
||||
//Orca: disable infill_direction/solid_infill_direction if sparse_infill_rotate_template/solid_infill_rotate_template is not empty value and adaptive cubic/support cubic infill pattern is not selected
|
||||
toggle_field("sparse_infill_rotate_template", !FillAdaptive);
|
||||
toggle_field("infill_direction", config->opt_string("sparse_infill_rotate_template") == "" && !FillAdaptive);
|
||||
toggle_field("solid_infill_direction", config->opt_string("solid_infill_rotate_template") == "");
|
||||
|
||||
|
||||
|
||||
toggle_line("infill_overhang_angle", config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ipLateralHoneycomb);
|
||||
|
||||
std::string printer_type = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
|
||||
|
||||
@@ -868,24 +868,13 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle)
|
||||
|
||||
m_gl_data_initialized = true;
|
||||
|
||||
if (preset_bundle)
|
||||
m_nozzle_nums = preset_bundle->get_printer_extruder_count();
|
||||
bool multimaterial = preset_bundle->filament_presets.empty() ? 0 : preset_bundle->filament_presets.size() > 1;
|
||||
|
||||
// set to color print by default if use multi extruders
|
||||
if (m_nozzle_nums > 1) {
|
||||
m_view_type_sel = std::distance(view_type_items.begin(),
|
||||
std::find(view_type_items.begin(), view_type_items.end(), EViewType::Summary));
|
||||
set_view_type(EViewType::Summary);
|
||||
} else if (multimaterial) {
|
||||
m_view_type_sel = std::distance(view_type_items.begin(),
|
||||
std::find(view_type_items.begin(), view_type_items.end(), EViewType::ColorPrint));
|
||||
set_view_type(EViewType::ColorPrint);
|
||||
} else {
|
||||
m_view_type_sel = std::distance(view_type_items.begin(),
|
||||
std::find(view_type_items.begin(), view_type_items.end(), EViewType::FeatureType));
|
||||
set_view_type(EViewType::FeatureType);
|
||||
}
|
||||
// Orca:
|
||||
// Default view type at first slice.
|
||||
// May be overridden in load() once we know how many tools are actually used in the G-code.
|
||||
m_nozzle_nums = preset_bundle ? preset_bundle->get_printer_extruder_count() : 1;
|
||||
auto it = std::find(view_type_items.begin(), view_type_items.end(), EViewType::FeatureType);
|
||||
m_view_type_sel = (it != view_type_items.end()) ? std::distance(view_type_items.begin(), it) : 0;
|
||||
set_view_type(EViewType::FeatureType);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": finished");
|
||||
}
|
||||
@@ -995,6 +984,20 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
||||
m_max_print_height = gcode_result.printable_height;
|
||||
|
||||
load_toolpaths(gcode_result, build_volume, exclude_bounding_box);
|
||||
|
||||
// ORCA: Only show filament/color print preview if more than one tool/extruder is actually used in the toolpaths.
|
||||
// Only reset back to Toolpaths (FeatureType) if we are currently in ColorPrint and this load is single-tool.
|
||||
if (m_extruder_ids.size() > 1) {
|
||||
auto it = std::find(view_type_items.begin(), view_type_items.end(), EViewType::ColorPrint);
|
||||
if (it != view_type_items.end())
|
||||
m_view_type_sel = std::distance(view_type_items.begin(), it);
|
||||
set_view_type(EViewType::ColorPrint);
|
||||
} else if (m_view_type == EViewType::ColorPrint) {
|
||||
auto it = std::find(view_type_items.begin(), view_type_items.end(), EViewType::FeatureType);
|
||||
if (it != view_type_items.end())
|
||||
m_view_type_sel = std::distance(view_type_items.begin(), it);
|
||||
set_view_type(EViewType::FeatureType);
|
||||
}
|
||||
|
||||
// BBS: data for rendering color arrangement recommendation
|
||||
m_nozzle_nums = print.config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||
|
||||
@@ -108,7 +108,12 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
try{
|
||||
|
||||
if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) {
|
||||
auto vec_new = std::make_unique<ConfigOptionBoolsNullable>(1, boost::any_cast<unsigned char>(value) );
|
||||
const auto v = boost::any_cast<unsigned char>(value);
|
||||
auto vec_new = std::make_unique<ConfigOptionBoolsNullable>(1, v);
|
||||
if (v == ConfigOptionBoolsNullable::nil_value()) {
|
||||
vec_new->set_at_to_nil(0);
|
||||
}
|
||||
|
||||
config.option<ConfigOptionBoolsNullable>(opt_key)->set_at(vec_new.get(), opt_index, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,14 @@ ImageDPIFrame::ImageDPIFrame()
|
||||
#ifdef __APPLE__
|
||||
SetWindowStyleFlag(GetWindowStyleFlag() | wxSTAY_ON_TOP);
|
||||
#endif
|
||||
|
||||
// ORCA add border
|
||||
Bind(wxEVT_PAINT, [this](wxPaintEvent& evt) {
|
||||
wxPaintDC dc(this);
|
||||
dc.SetPen(StateColor::darkModeColorFor(wxColour("#DBDBDB")));
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 0);
|
||||
});
|
||||
|
||||
m_sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
|
||||
@@ -427,16 +427,18 @@ void UpdateJob::update_volume(ModelVolume *volume, TriangleMesh &&mesh, const Da
|
||||
volume->set_new_unique_id();
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// write data from base into volume
|
||||
base.write(*volume);
|
||||
|
||||
GUI_App &app = wxGetApp(); // may be move to input
|
||||
|
||||
if (volume->name != base.volume_name) {
|
||||
volume->name = base.volume_name;
|
||||
// write data from base into volume
|
||||
base.write(*volume);
|
||||
|
||||
const ObjectList *obj_list = app.obj_list();
|
||||
if (obj_list != nullptr)
|
||||
update_name_in_list(*obj_list, *volume);
|
||||
} else {
|
||||
// write data from base into volume
|
||||
base.write(*volume);
|
||||
}
|
||||
|
||||
ModelObject *object = volume->get_object();
|
||||
|
||||
@@ -53,7 +53,7 @@ OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent,
|
||||
// BBS: new font
|
||||
m_font = Label::Body_14;
|
||||
SetFont(m_font);
|
||||
m_em_unit = em_unit(m_parent);
|
||||
m_em_unit = em_unit(m_parent);
|
||||
m_v_gap = lround(1.2 * m_em_unit);
|
||||
m_v_gap2 = lround(0.8 * m_em_unit);
|
||||
m_h_gap = lround(0.2 * m_em_unit);
|
||||
@@ -597,7 +597,7 @@ void OG_CustomCtrl::msw_rescale()
|
||||
SetFont(m_font);
|
||||
m_em_unit = em_unit(m_parent);
|
||||
m_v_gap = lround(1.2 * m_em_unit);
|
||||
m_v_gap2 = lround(0.8 * m_em_unit);
|
||||
m_v_gap2 = lround(0.8 * m_em_unit);
|
||||
m_h_gap = lround(0.2 * m_em_unit);
|
||||
|
||||
//m_bmp_mode_sz = create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12).GetSize();
|
||||
@@ -992,7 +992,7 @@ wxPoint OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBi
|
||||
pos.y += lround((height - get_bitmap_size(bmp_undo).GetHeight()) / 2);
|
||||
}
|
||||
#endif
|
||||
wxCoord h_pos = pos.x;
|
||||
wxCoord h_pos = pos.x - ctrl->m_h_gap; // Orca: adjust position to the left
|
||||
wxCoord v_pos = pos.y;
|
||||
|
||||
#ifndef DISABLE_UNDO_SYS
|
||||
|
||||
@@ -220,9 +220,14 @@ wxDEFINE_EVENT(EVT_NOTICE_FULL_SCREEN_CHANGED, IntEvent);
|
||||
|
||||
static string get_diameter_string(float diameter)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << std::fixed << std::setprecision(1) << diameter;
|
||||
return stream.str();
|
||||
std::ostringstream stream; // ORCA ensure 0.25 returned as 0.25. previous code returned as 0.2 because of std::setprecision(1)
|
||||
stream << std::fixed << std::setprecision(2) << diameter; // Use 2 decimals to capture 0.25 / 0.15 reliably
|
||||
std::string s = stream.str();
|
||||
if (s.find('.') != std::string::npos) { // Remove trailing zeros, but keep at least one decimal if needed
|
||||
s.erase(s.find_last_not_of('0') + 1);
|
||||
if (s.back() == '.') s += '0'; // Ensure "1." → "1.0"
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
|
||||
@@ -574,7 +579,9 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
|
||||
// ORCA show plate type combo box only when its supported
|
||||
PresetBundle &preset_bundle = *wxGetApp().preset_bundle;
|
||||
auto cfg = preset_bundle.printers.get_edited_preset().config;
|
||||
panel_printer_bed->Show(isBBL || cfg.opt_bool("support_multi_bed_types"));
|
||||
// Orca: we use preset_bundle.is_bbl_vendor() instead of isBBL to determine if the plate type combo box should be shown
|
||||
// ref: https://github.com/OrcaSlicer/OrcaSlicer/pull/11610#discussion_r2607411847
|
||||
panel_printer_bed->Show(preset_bundle.is_bbl_vendor() || cfg.opt_bool("support_multi_bed_types"));
|
||||
|
||||
extruder_dual_sizer->Show(isDual);
|
||||
|
||||
@@ -1230,7 +1237,8 @@ bool Sidebar::priv::switch_diameter(bool single)
|
||||
}
|
||||
auto preset = wxGetApp().preset_bundle->get_similar_printer_preset({}, diameter.ToStdString());
|
||||
if (preset == nullptr) {
|
||||
MessageDialog dlg(this->plater, "", "");
|
||||
// ORCA add a text. this appears when user tries to change nozzle value but config doesnt have a inherited or compatible preset
|
||||
MessageDialog dlg(this->plater, _L("Configuration incompatible"), _L("Warning"), wxICON_WARNING | wxOK);
|
||||
dlg.ShowModal();
|
||||
return false;
|
||||
}
|
||||
@@ -2536,9 +2544,18 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
p->layout_printer(preset_bundle.use_bbl_network(), isBBL && is_dual_extruder);
|
||||
auto diameters = wxGetApp().preset_bundle->printers.diameters_of_selected_printer();
|
||||
auto diameter = printer_preset.config.opt_string("printer_variant");
|
||||
auto update_extruder_diameter = [&diameters, &diameter](ExtruderGroup & extruder) {
|
||||
auto update_extruder_diameter = [&diameters, &diameter, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) {
|
||||
extruder.combo_diameter->Clear();
|
||||
int select = -1;
|
||||
// ORCA if user defined a custom nozzle in printer config select it instead inherited one. this will show correct nozzle diameter in combobox if its exist in nozzle diameters list
|
||||
auto nozzle_dia = get_diameter_string(nozzle_diameter->values[extruder_index]);
|
||||
if(nozzle_dia != diameter && std::find(diameters.begin(), diameters.end(), nozzle_dia) != diameters.end())
|
||||
diameter = nozzle_dia;
|
||||
// ORCA try to add nozzle diameter from config if list is empty. fixes blank nozzle combo box when preset has no alias
|
||||
if(diameters[0].empty() && !nozzle_dia.empty()){
|
||||
diameters[0] = nozzle_dia;
|
||||
diameter = nozzle_dia;
|
||||
}
|
||||
for (size_t i = 0; i < diameters.size(); ++i) {
|
||||
if (diameters[i] == diameter)
|
||||
select = extruder.combo_diameter->GetCount();
|
||||
@@ -2552,14 +2569,14 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
AMSCountPopupWindow::UpdateAMSCount(0, p->left_extruder);
|
||||
AMSCountPopupWindow::UpdateAMSCount(1, p->right_extruder);
|
||||
//if (!p->is_switching_diameter) {
|
||||
update_extruder_diameter(*p->left_extruder);
|
||||
update_extruder_diameter(*p->right_extruder);
|
||||
update_extruder_diameter(0, *p->left_extruder);
|
||||
update_extruder_diameter(1, *p->right_extruder);
|
||||
//}
|
||||
p->image_printer_bed->SetBitmap(create_scaled_bitmap(image_path, this, PRINTER_THUMBNAIL_SIZE.GetHeight()));
|
||||
} else {
|
||||
AMSCountPopupWindow::UpdateAMSCount(0, p->single_extruder);
|
||||
//if (!p->is_switching_diameter)
|
||||
update_extruder_diameter(*p->single_extruder);
|
||||
update_extruder_diameter(0, *p->single_extruder);
|
||||
|
||||
// ORCA sync unified nozzle combo box
|
||||
p->combo_nozzle_dia->Clear();
|
||||
|
||||
@@ -353,9 +353,9 @@ void Tab::create_preset_tab()
|
||||
|
||||
});
|
||||
|
||||
m_undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_roll_back_value(); }));
|
||||
//m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_roll_back_value(true); }));
|
||||
/* m_search_btn->Bind(wxEVT_BUTTON, [](wxCommandEvent) { wxGetApp().plater()->search(false); });*/
|
||||
m_undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent&) { on_roll_back_value(); }));
|
||||
//m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent&) { on_roll_back_value(true); }));
|
||||
/* m_search_btn->Bind(wxEVT_BUTTON, [](wxCommandEvent&) { wxGetApp().plater()->search(false); });*/
|
||||
|
||||
// Colors for ui "decoration"
|
||||
m_sys_label_clr = wxGetApp().get_label_clr_sys();
|
||||
@@ -540,14 +540,14 @@ void Tab::create_preset_tab()
|
||||
m_hsizer->Add(m_page_view, 1, wxEXPAND | wxLEFT, 5);*/
|
||||
|
||||
//m_btn_compare_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { compare_preset(); }));
|
||||
m_btn_save_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { save_preset(); }));
|
||||
m_btn_delete_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { delete_preset(); }));
|
||||
m_btn_save_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { save_preset(); }));
|
||||
m_btn_delete_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { delete_preset(); }));
|
||||
/*m_btn_hide_incompatible_presets->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) {
|
||||
toggle_show_hide_incompatible();
|
||||
}));
|
||||
|
||||
if (m_btn_edit_ph_printer)
|
||||
m_btn_edit_ph_printer->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) {
|
||||
m_btn_edit_ph_printer->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||
if (m_preset_bundle->physical_printers.has_selection())
|
||||
m_presets_choice->edit_physical_printer();
|
||||
else
|
||||
@@ -892,7 +892,8 @@ void Tab::decorate()
|
||||
void Tab::filter_diff_option(std::vector<std::string> &options)
|
||||
{
|
||||
for (auto &opt : options) {
|
||||
if (opt.find_last_of('#') == std::string::npos) continue;
|
||||
const auto hash_pos = opt.find_last_of('#');
|
||||
if (hash_pos == std::string::npos) continue;
|
||||
bool found = false;
|
||||
for (auto page : m_pages) {
|
||||
if (auto iter = page->m_opt_id_map.find(opt); iter != page->m_opt_id_map.end()) {
|
||||
@@ -901,7 +902,7 @@ void Tab::filter_diff_option(std::vector<std::string> &options)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) opt.clear();
|
||||
if (!found) opt = opt.substr(0, hash_pos);
|
||||
}
|
||||
options.erase(std::remove(options.begin(), options.end(), ""), options.end());
|
||||
}
|
||||
@@ -912,7 +913,7 @@ void Tab::update_changed_ui()
|
||||
if (m_postpone_update_ui)
|
||||
return;
|
||||
|
||||
const bool deep_compare = (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_PRINT
|
||||
const bool deep_compare = (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_FILAMENT
|
||||
|| m_type == Preset::TYPE_SLA_MATERIAL || m_type == Preset::TYPE_MODEL);
|
||||
auto dirty_options = m_presets->current_dirty_options(deep_compare);
|
||||
auto nonsys_options = m_presets->current_different_from_parent_options(deep_compare);
|
||||
@@ -3559,7 +3560,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
auto append_retraction_option = [this, retraction_optgroup](const std::string& opt_key, int opt_index)
|
||||
{
|
||||
Line line {"",""};
|
||||
line = retraction_optgroup->create_single_option_line(retraction_optgroup->get_option(opt_key));
|
||||
line = retraction_optgroup->create_single_option_line(retraction_optgroup->get_option(opt_key, opt_index));
|
||||
|
||||
line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(retraction_optgroup), opt_key, opt_index](wxWindow* parent) {
|
||||
auto check_box = new ::CheckBox(parent); // ORCA modernize checkboxes
|
||||
@@ -3581,6 +3582,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
}
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}, check_box->GetId());
|
||||
|
||||
m_overrides_options[opt_key] = check_box;
|
||||
@@ -3616,7 +3618,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
auto append_ironing_option = [this, ironing_optgroup](const std::string& opt_key, int opt_index)
|
||||
{
|
||||
Line line {"",""};
|
||||
line = ironing_optgroup->create_single_option_line(ironing_optgroup->get_option(opt_key));
|
||||
line = ironing_optgroup->create_single_option_line(ironing_optgroup->get_option(opt_key, opt_index));
|
||||
|
||||
line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(ironing_optgroup), opt_key, opt_index](wxWindow* parent) {
|
||||
auto check_box = new ::CheckBox(parent); // ORCA modernize checkboxes
|
||||
@@ -3682,6 +3684,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
}
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}, check_box->GetId());
|
||||
|
||||
m_overrides_options[opt_key] = check_box;
|
||||
@@ -3888,8 +3891,8 @@ void TabFilament::build()
|
||||
optgroup = page->new_optgroup(L("Print temperature"), L"param_extruder_temp");
|
||||
line = { L("Nozzle"), L("Nozzle temperature when printing") };
|
||||
line.label_path = "material_temperatures#nozzle";
|
||||
line.append_option(optgroup->get_option("nozzle_temperature_initial_layer"));
|
||||
line.append_option(optgroup->get_option("nozzle_temperature"));
|
||||
line.append_option(optgroup->get_option("nozzle_temperature_initial_layer", 0));
|
||||
line.append_option(optgroup->get_option("nozzle_temperature", 0));
|
||||
optgroup->append_line(line);
|
||||
|
||||
optgroup = page->new_optgroup(L("Bed temperature"), L"param_bed_temp");
|
||||
@@ -3968,7 +3971,7 @@ void TabFilament::build()
|
||||
//BBS
|
||||
optgroup = page->new_optgroup(L("Volumetric speed limitation"), L"param_volumetric_speed");
|
||||
optgroup->append_single_option_line("filament_adaptive_volumetric_speed", "material_volumetric_speed_limitation#adaptive-volumetric-speed", 0);
|
||||
optgroup->append_single_option_line("filament_max_volumetric_speed", "material_volumetric_speed_limitation#max-volumetric-speed");
|
||||
optgroup->append_single_option_line("filament_max_volumetric_speed", "material_volumetric_speed_limitation#max-volumetric-speed", 0);
|
||||
|
||||
//line = { "", "" };
|
||||
//line.full_width = 1;
|
||||
@@ -4140,6 +4143,9 @@ void TabFilament::reload_config()
|
||||
this->compatible_widget_reload(m_compatible_printers);
|
||||
this->compatible_widget_reload(m_compatible_prints);
|
||||
Tab::reload_config();
|
||||
|
||||
// Recompute derived override UI from the newly loaded config
|
||||
update_filament_overrides_page(&m_preset_bundle->printers.get_edited_preset().config);
|
||||
}
|
||||
|
||||
//void TabFilament::update_volumetric_flow_preset_hints()
|
||||
@@ -6698,18 +6704,18 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
|
||||
this->update_changed_ui();
|
||||
};
|
||||
|
||||
deps.checkbox_title->Bind(wxEVT_LEFT_DOWN,([this, &deps, on_toggle](wxMouseEvent e) {
|
||||
deps.checkbox_title->Bind(wxEVT_LEFT_DOWN,([this, &deps, on_toggle](wxMouseEvent& e) {
|
||||
if (e.GetEventType() == wxEVT_LEFT_DCLICK) return;
|
||||
on_toggle(!deps.checkbox->GetValue());
|
||||
e.Skip();
|
||||
}));
|
||||
|
||||
deps.checkbox_title->Bind(wxEVT_LEFT_DCLICK,([this, &deps, on_toggle](wxMouseEvent e) {
|
||||
deps.checkbox_title->Bind(wxEVT_LEFT_DCLICK,([this, &deps, on_toggle](wxMouseEvent& e) {
|
||||
on_toggle(!deps.checkbox->GetValue());
|
||||
e.Skip();
|
||||
}));
|
||||
|
||||
deps.checkbox->Bind(wxEVT_TOGGLEBUTTON, ([this, on_toggle](wxCommandEvent e) {
|
||||
deps.checkbox->Bind(wxEVT_TOGGLEBUTTON, ([this, on_toggle](wxCommandEvent& e) {
|
||||
on_toggle(e.IsChecked());
|
||||
e.Skip();
|
||||
}), deps.checkbox->GetId());
|
||||
@@ -6734,7 +6740,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
|
||||
}
|
||||
*/
|
||||
|
||||
deps.btn->Bind(wxEVT_BUTTON, ([this, parent, &deps](wxCommandEvent e)
|
||||
deps.btn->Bind(wxEVT_BUTTON, ([this, parent, &deps](wxCommandEvent& e)
|
||||
{
|
||||
// Collect names of non-default non-external profiles.
|
||||
PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
@@ -6816,7 +6822,7 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) {
|
||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) {
|
||||
bool is_configed_by_BBL = PresetUtils::system_printer_bed_model(m_preset_bundle->printers.get_edited_preset()).size() > 0;
|
||||
BedShapeDialog dlg(this);
|
||||
dlg.build_dialog(m_config->option<ConfigOptionPoints>("printable_area")->values,
|
||||
|
||||
Reference in New Issue
Block a user