Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_extended_m73
This commit is contained in:
commit
645e5b6862
27 changed files with 402 additions and 275 deletions
|
@ -1581,89 +1581,109 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
|||
{
|
||||
// extrusion roles
|
||||
|
||||
// in older versions the comments did not contain the key 'feature'
|
||||
std::string_view cmt = comment;
|
||||
size_t pos = cmt.find(" feature");
|
||||
if (pos == 0)
|
||||
cmt.remove_prefix(8);
|
||||
|
||||
// ; skirt
|
||||
size_t pos = comment.find(" skirt");
|
||||
pos = cmt.find(" skirt");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSkirt;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; outer perimeter
|
||||
pos = comment.find(" outer perimeter");
|
||||
pos = cmt.find(" outer perimeter");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erExternalPerimeter;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; inner perimeter
|
||||
pos = comment.find(" inner perimeter");
|
||||
pos = cmt.find(" inner perimeter");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erPerimeter;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; gap fill
|
||||
pos = comment.find(" gap fill");
|
||||
pos = cmt.find(" gap fill");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erGapFill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; infill
|
||||
pos = comment.find(" infill");
|
||||
pos = cmt.find(" infill");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erInternalInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; solid layer
|
||||
pos = comment.find(" solid layer");
|
||||
pos = cmt.find(" solid layer");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
m_extrusion_role = erSolidInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; bridge
|
||||
pos = comment.find(" bridge");
|
||||
pos = cmt.find(" bridge");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erBridgeInfill;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; support
|
||||
pos = comment.find(" support");
|
||||
pos = cmt.find(" support");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSupportMaterial;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; dense support
|
||||
pos = cmt.find(" dense support");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSupportMaterialInterface;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; prime pillar
|
||||
pos = comment.find(" prime pillar");
|
||||
pos = cmt.find(" prime pillar");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erWipeTower;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; ooze shield
|
||||
pos = comment.find(" ooze shield");
|
||||
pos = cmt.find(" ooze shield");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
m_extrusion_role = erNone; // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; raft
|
||||
pos = comment.find(" raft");
|
||||
pos = cmt.find(" raft");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erSkirt;
|
||||
m_extrusion_role = erSupportMaterial;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; internal single extrusion
|
||||
pos = cmt.find(" internal single extrusion");
|
||||
if (pos == 0) {
|
||||
m_extrusion_role = erNone; // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
// geometry
|
||||
// ; tool
|
||||
std::string tag = " tool";
|
||||
pos = comment.find(tag);
|
||||
pos = cmt.find(tag);
|
||||
if (pos == 0) {
|
||||
const std::string_view data = comment.substr(pos + tag.length());
|
||||
const std::string_view data = cmt.substr(pos + tag.length());
|
||||
std::string h_tag = "H";
|
||||
size_t h_start = data.find(h_tag);
|
||||
size_t h_end = data.find_first_of(' ', h_start);
|
||||
|
@ -1684,10 +1704,10 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
|||
|
||||
// ; layer
|
||||
tag = " layer";
|
||||
pos = comment.find(tag);
|
||||
pos = cmt.find(tag);
|
||||
if (pos == 0) {
|
||||
// skip lines "; layer end"
|
||||
const std::string_view data = comment.substr(pos + tag.length());
|
||||
const std::string_view data = cmt.substr(pos + tag.length());
|
||||
size_t end_start = data.find("end");
|
||||
if (end_start == data.npos)
|
||||
++m_layer_id;
|
||||
|
@ -2662,7 +2682,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
|
|||
{
|
||||
MoveVertex vertex = {
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
m_line_id,
|
||||
(type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : m_line_id,
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
type,
|
||||
m_extrusion_role,
|
||||
|
|
|
@ -122,7 +122,7 @@ static bool clip_narrow_corner(
|
|||
} else {
|
||||
assert(backward == Free);
|
||||
p02 = it0.prev()->cast<int64_t>();
|
||||
if (cross2(p0 - p2, p02 - p2) > 0)
|
||||
if (cross2(p02 - p2, p0 - p2) > 0)
|
||||
backward = Blocked;
|
||||
else {
|
||||
// New clipping edge lenght.
|
||||
|
@ -141,14 +141,37 @@ static bool clip_narrow_corner(
|
|||
}
|
||||
}
|
||||
|
||||
assert(dist2_current <= shortcut_length2);
|
||||
assert(polygon.size() >= 2);
|
||||
assert(polygon.size() == 2 || forward == Blocked || forward == Far);
|
||||
assert(polygon.size() == 2 || backward == Blocked || backward == Far);
|
||||
|
||||
if (polygon.size() <= 3) {
|
||||
// A hole degenerated to an empty polygon, or a tiny triangle remained.
|
||||
assert(polygon.size() < 3 || (forward == Blocked && backward == Blocked) || (forward == Far && backward == Far));
|
||||
if (polygon.size() < 3 || forward == Far) {
|
||||
assert(polygon.size() < 3 || dist2_current <= shortcut_length2);
|
||||
bool blocked = forward == Blocked || backward == Blocked;
|
||||
assert(polygon.size() < 3 ||
|
||||
// Remaining triangle is CCW oriented. Both sides must be "blocked", but the other side may have not been
|
||||
// updated after the the p02 / p22 became united into a single point.
|
||||
blocked ||
|
||||
// Remaining triangle is concave, however both of its arms are long.
|
||||
(forward == Far && backward == Far));
|
||||
#ifndef _NDEBUG
|
||||
if (polygon.size() == 3) {
|
||||
// Verify that the remaining triangle is CCW or CW.
|
||||
p02 = it0.prev()->cast<int64_t>();
|
||||
p22 = it2.next()->cast<int64_t>();
|
||||
assert(p02 == p22);
|
||||
auto orient1 = cross2(p02 - p2, p0 - p2);
|
||||
auto orient2 = cross2(p2 - p0, p22 - p0);
|
||||
assert(orient1 > 0 == blocked);
|
||||
assert(orient2 > 0 == blocked);
|
||||
}
|
||||
#endif // _NDEBUG
|
||||
if (polygon.size() < 3 || (forward == Far && backward == Far)) {
|
||||
polygon.clear();
|
||||
} else {
|
||||
// The remaining triangle is CCW oriented, keep it.
|
||||
assert(forward == Blocked || backward == Blocked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -168,7 +191,7 @@ static bool clip_narrow_corner(
|
|||
} else if (forward == Blocked || backward == Blocked) {
|
||||
// One side is far, the other blocked.
|
||||
assert(forward == Far || backward == Far);
|
||||
if (backward == Far) {
|
||||
if (forward == Far) {
|
||||
// Sort, so we will clip the 1st edge.
|
||||
std::swap(p0, p2);
|
||||
std::swap(p02, p22);
|
||||
|
@ -177,6 +200,10 @@ static bool clip_narrow_corner(
|
|||
// Circle intersects a line at two points, however because |p2 - p0| < shortcut_length,
|
||||
// only the second intersection is valid. Because |p2 - p02| > shortcut_length, such
|
||||
// intersection should always be found on (p0, p02).
|
||||
#ifndef NDEBUG
|
||||
auto dfar2 = (p02 - p2).squaredNorm();
|
||||
assert(dfar2 >= shortcut_length2);
|
||||
#endif // NDEBUG
|
||||
const Vec2d v = (p02 - p0).cast<double>();
|
||||
const Vec2d d = (p0 - p2).cast<double>();
|
||||
const double a = v.squaredNorm();
|
||||
|
@ -273,15 +300,17 @@ void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled)
|
|||
Point pt_new = p1 + (t * v2d).cast<coord_t>();
|
||||
#ifndef NDEBUG
|
||||
double d2new = (pt_new - (swap ? p2 : p0)).cast<double>().squaredNorm();
|
||||
assert(std::abs(d2new - clip_dist_scaled2) < sqr(10. * SCALED_EPSILON));
|
||||
assert(std::abs(d2new - clip_dist_scaled2) < 1e-5 * clip_dist_scaled2);
|
||||
#endif // NDEBUG
|
||||
it2.insert(pt_new);
|
||||
} else {
|
||||
// Cut the corner with a line perpendicular to the bisector.
|
||||
double t = sqrt(0.25 * clip_dist_scaled2 / d2);
|
||||
assert(t > 0. && t < 1.);
|
||||
Point p0 = p1 + (v1d * t).cast<coord_t>();
|
||||
Point p2 = p1 + (v2d * (t * lv2 / lv1)).cast<coord_t>();
|
||||
double t2 = t * lv1 / lv2;
|
||||
assert(t > 0. && t < 1.);
|
||||
assert(t2 > 0. && t2 < 1.);
|
||||
Point p0 = p1 + (v1d * t ).cast<coord_t>();
|
||||
Point p2 = p1 + (v2d * t2).cast<coord_t>();
|
||||
if (swap)
|
||||
std::swap(p0, p2);
|
||||
it2.insert(p2).insert(p0);
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
}
|
||||
|
||||
void advance_front() {
|
||||
assert(!this->empty());
|
||||
assert(! this->empty());
|
||||
if (m_begin == m_end)
|
||||
this->make_empty();
|
||||
else
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
}
|
||||
|
||||
void retract_back() {
|
||||
assert(!this->empty());
|
||||
assert(! this->empty());
|
||||
if (m_begin == m_end)
|
||||
this->make_empty();
|
||||
else
|
||||
|
@ -101,13 +101,13 @@ public:
|
|||
}
|
||||
|
||||
MutablePolygon::iterator remove_front(MutablePolygon::iterator it) {
|
||||
if (m_begin == it)
|
||||
if (! this->empty() && m_begin == it)
|
||||
this->advance_front();
|
||||
return it.remove();
|
||||
}
|
||||
|
||||
MutablePolygon::iterator remove_back(MutablePolygon::iterator it) {
|
||||
if (m_end == it)
|
||||
if (! this->empty() && m_end == it)
|
||||
this->retract_back();
|
||||
return it.remove();
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||
"min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing",
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_style",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
|
||||
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
|
||||
"support_material_contact_distance", "support_material_bottom_contact_distance",
|
||||
|
|
|
@ -2419,6 +2419,20 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(60));
|
||||
|
||||
def = this->add("support_material_style", coEnum);
|
||||
def->label = L("Style");
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("Style and shape of the support towers. Projecting the supports into a regular grid "
|
||||
"will create more stable supports, while snug support towers will save material and reduce "
|
||||
"object scarring.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<SupportMaterialStyle>::get_enum_values();
|
||||
def->enum_values.push_back("grid");
|
||||
def->enum_values.push_back("snug");
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->enum_labels.push_back(L("Snug"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<SupportMaterialStyle>(smsGrid));
|
||||
|
||||
def = this->add("support_material_synchronize_layers", coBool);
|
||||
def->label = L("Synchronize with object layers");
|
||||
def->category = L("Support material");
|
||||
|
|
|
@ -65,6 +65,10 @@ enum SupportMaterialPattern {
|
|||
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
|
||||
};
|
||||
|
||||
enum SupportMaterialStyle {
|
||||
smsGrid, smsSnug,
|
||||
};
|
||||
|
||||
enum SupportMaterialInterfacePattern {
|
||||
smipAuto, smipRectilinear, smipConcentric,
|
||||
};
|
||||
|
@ -211,6 +215,15 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialPa
|
|||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialStyle>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["grid"] = smsGrid;
|
||||
keys_map["snug"] = smsSnug;
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialInterfacePattern>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
|
@ -519,6 +532,7 @@ public:
|
|||
// Spacing between support material lines (the hatching distance).
|
||||
ConfigOptionFloat support_material_spacing;
|
||||
ConfigOptionFloat support_material_speed;
|
||||
ConfigOptionEnum<SupportMaterialStyle> support_material_style;
|
||||
ConfigOptionBool support_material_synchronize_layers;
|
||||
// Overhang angle threshold.
|
||||
ConfigOptionInt support_material_threshold;
|
||||
|
@ -570,6 +584,7 @@ protected:
|
|||
OPT_PTR(support_material_interface_pattern);
|
||||
OPT_PTR(support_material_spacing);
|
||||
OPT_PTR(support_material_speed);
|
||||
OPT_PTR(support_material_style);
|
||||
OPT_PTR(support_material_synchronize_layers);
|
||||
OPT_PTR(support_material_xy_spacing);
|
||||
OPT_PTR(support_material_threshold);
|
||||
|
|
|
@ -588,6 +588,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||
|| opt_key == "support_material_interface_extruder"
|
||||
|| opt_key == "support_material_interface_spacing"
|
||||
|| opt_key == "support_material_pattern"
|
||||
|| opt_key == "support_material_style"
|
||||
|| opt_key == "support_material_xy_spacing"
|
||||
|| opt_key == "support_material_spacing"
|
||||
|| opt_key == "support_material_synchronize_layers"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Fill/FillBase.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "MutablePolygon.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
@ -667,17 +668,19 @@ Polygons collect_slices_outer(const Layer &layer)
|
|||
|
||||
struct SupportGridParams {
|
||||
SupportGridParams(const PrintObjectConfig &object_config, const Flow &support_material_flow) :
|
||||
style(object_config.support_material_style.value),
|
||||
grid_resolution(object_config.support_material_spacing.value + support_material_flow.spacing()),
|
||||
support_angle(Geometry::deg2rad(object_config.support_material_angle.value)),
|
||||
extrusion_width(support_material_flow.spacing()),
|
||||
expansion_to_slice(coord_t(support_material_flow.scaled_spacing() / 2 + 5)),
|
||||
expansion_to_propagate(-3) {}
|
||||
|
||||
double grid_resolution;
|
||||
double support_angle;
|
||||
double extrusion_width;
|
||||
coord_t expansion_to_slice;
|
||||
coord_t expansion_to_propagate;
|
||||
SupportMaterialStyle style;
|
||||
double grid_resolution;
|
||||
double support_angle;
|
||||
double extrusion_width;
|
||||
coord_t expansion_to_slice;
|
||||
coord_t expansion_to_propagate;
|
||||
};
|
||||
|
||||
class SupportGridPattern
|
||||
|
@ -689,75 +692,88 @@ public:
|
|||
// Trimming polygons, to trim the stretched support islands. support_polygons were already trimmed with trimming_polygons.
|
||||
const Polygons *trimming_polygons,
|
||||
const SupportGridParams ¶ms) :
|
||||
m_style(params.style),
|
||||
m_support_polygons(support_polygons), m_trimming_polygons(trimming_polygons),
|
||||
m_support_spacing(params.grid_resolution), m_support_angle(params.support_angle)
|
||||
{
|
||||
if (m_support_angle != 0.) {
|
||||
// Create a copy of the rotated contours.
|
||||
m_support_polygons_rotated = *support_polygons;
|
||||
m_trimming_polygons_rotated = *trimming_polygons;
|
||||
m_support_polygons = &m_support_polygons_rotated;
|
||||
m_trimming_polygons = &m_trimming_polygons_rotated;
|
||||
polygons_rotate(m_support_polygons_rotated, - params.support_angle);
|
||||
polygons_rotate(m_trimming_polygons_rotated, - params.support_angle);
|
||||
}
|
||||
|
||||
// Resolution of the sparse support grid.
|
||||
coord_t grid_resolution = coord_t(scale_(m_support_spacing));
|
||||
BoundingBox bbox = get_extents(*m_support_polygons);
|
||||
bbox.offset(20);
|
||||
// Align the bounding box with the sparse support grid.
|
||||
bbox.align_to_grid(grid_resolution);
|
||||
|
||||
#ifdef SUPPORT_USE_AGG_RASTERIZER
|
||||
m_bbox = bbox;
|
||||
// Oversample the grid to avoid leaking of supports through or around the object walls.
|
||||
int oversampling = std::min(8, int(scale_(m_support_spacing) / (scale_(params.extrusion_width) + 100)));
|
||||
m_pixel_size = scale_(m_support_spacing / oversampling);
|
||||
assert(scale_(params.extrusion_width) + 20 < m_pixel_size);
|
||||
// Add one empty column / row boundaries.
|
||||
m_bbox.offset(m_pixel_size);
|
||||
// Grid size fitting the support polygons plus one pixel boundary around the polygons.
|
||||
Vec2i grid_size_raw(int(ceil((m_bbox.max.x() - m_bbox.min.x()) / m_pixel_size)),
|
||||
int(ceil((m_bbox.max.y() - m_bbox.min.y()) / m_pixel_size)));
|
||||
// Overlay macro blocks of (oversampling x oversampling) over the grid.
|
||||
Vec2i grid_blocks((grid_size_raw.x() + oversampling - 1 - 2) / oversampling,
|
||||
(grid_size_raw.y() + oversampling - 1 - 2) / oversampling);
|
||||
// and resize the grid to fit the macro blocks + one pixel boundary.
|
||||
m_grid_size = grid_blocks * oversampling + Vec2i(2, 2);
|
||||
assert(m_grid_size.x() >= grid_size_raw.x());
|
||||
assert(m_grid_size.y() >= grid_size_raw.y());
|
||||
m_grid2 = rasterize_polygons(m_grid_size, m_pixel_size, m_bbox.min, *m_support_polygons);
|
||||
|
||||
seed_fill_block(m_grid2, m_grid_size,
|
||||
dilate_trimming_region(rasterize_polygons(m_grid_size, m_pixel_size, m_bbox.min, *m_trimming_polygons), m_grid_size),
|
||||
grid_blocks, oversampling);
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
switch (m_style) {
|
||||
case smsGrid:
|
||||
{
|
||||
static int irun;
|
||||
Slic3r::png::write_gray_to_file_scaled(debug_out_path("support-rasterizer-%d.png", irun++), m_grid_size.x(), m_grid_size.y(), m_grid2.data(), 4);
|
||||
}
|
||||
#endif // SLIC3R_DEBUG
|
||||
// Prepare the grid data, it will be reused when extracting support structures.
|
||||
if (m_support_angle != 0.) {
|
||||
// Create a copy of the rotated contours.
|
||||
m_support_polygons_rotated = *support_polygons;
|
||||
m_trimming_polygons_rotated = *trimming_polygons;
|
||||
m_support_polygons = &m_support_polygons_rotated;
|
||||
m_trimming_polygons = &m_trimming_polygons_rotated;
|
||||
polygons_rotate(m_support_polygons_rotated, - params.support_angle);
|
||||
polygons_rotate(m_trimming_polygons_rotated, - params.support_angle);
|
||||
}
|
||||
|
||||
#else // SUPPORT_USE_AGG_RASTERIZER
|
||||
// Create an EdgeGrid, initialize it with projection, initialize signed distance field.
|
||||
m_grid.set_bbox(bbox);
|
||||
m_grid.create(*m_support_polygons, grid_resolution);
|
||||
#if 0
|
||||
if (m_grid.has_intersecting_edges()) {
|
||||
// EdgeGrid fails to produce valid signed distance function for self-intersecting polygons.
|
||||
m_support_polygons_rotated = simplify_polygons(*m_support_polygons);
|
||||
m_support_polygons = &m_support_polygons_rotated;
|
||||
// Resolution of the sparse support grid.
|
||||
coord_t grid_resolution = coord_t(scale_(m_support_spacing));
|
||||
BoundingBox bbox = get_extents(*m_support_polygons);
|
||||
bbox.offset(20);
|
||||
// Align the bounding box with the sparse support grid.
|
||||
bbox.align_to_grid(grid_resolution);
|
||||
|
||||
#ifdef SUPPORT_USE_AGG_RASTERIZER
|
||||
m_bbox = bbox;
|
||||
// Oversample the grid to avoid leaking of supports through or around the object walls.
|
||||
int oversampling = std::min(8, int(scale_(m_support_spacing) / (scale_(params.extrusion_width) + 100)));
|
||||
m_pixel_size = scale_(m_support_spacing / oversampling);
|
||||
assert(scale_(params.extrusion_width) + 20 < m_pixel_size);
|
||||
// Add one empty column / row boundaries.
|
||||
m_bbox.offset(m_pixel_size);
|
||||
// Grid size fitting the support polygons plus one pixel boundary around the polygons.
|
||||
Vec2i grid_size_raw(int(ceil((m_bbox.max.x() - m_bbox.min.x()) / m_pixel_size)),
|
||||
int(ceil((m_bbox.max.y() - m_bbox.min.y()) / m_pixel_size)));
|
||||
// Overlay macro blocks of (oversampling x oversampling) over the grid.
|
||||
Vec2i grid_blocks((grid_size_raw.x() + oversampling - 1 - 2) / oversampling,
|
||||
(grid_size_raw.y() + oversampling - 1 - 2) / oversampling);
|
||||
// and resize the grid to fit the macro blocks + one pixel boundary.
|
||||
m_grid_size = grid_blocks * oversampling + Vec2i(2, 2);
|
||||
assert(m_grid_size.x() >= grid_size_raw.x());
|
||||
assert(m_grid_size.y() >= grid_size_raw.y());
|
||||
m_grid2 = rasterize_polygons(m_grid_size, m_pixel_size, m_bbox.min, *m_support_polygons);
|
||||
|
||||
seed_fill_block(m_grid2, m_grid_size,
|
||||
dilate_trimming_region(rasterize_polygons(m_grid_size, m_pixel_size, m_bbox.min, *m_trimming_polygons), m_grid_size),
|
||||
grid_blocks, oversampling);
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
{
|
||||
static int irun;
|
||||
Slic3r::png::write_gray_to_file_scaled(debug_out_path("support-rasterizer-%d.png", irun++), m_grid_size.x(), m_grid_size.y(), m_grid2.data(), 4);
|
||||
}
|
||||
#endif // SLIC3R_DEBUG
|
||||
|
||||
#else // SUPPORT_USE_AGG_RASTERIZER
|
||||
// Create an EdgeGrid, initialize it with projection, initialize signed distance field.
|
||||
m_grid.set_bbox(bbox);
|
||||
m_grid.create(*m_support_polygons, grid_resolution);
|
||||
// assert(! m_grid.has_intersecting_edges());
|
||||
printf("SupportGridPattern: fixing polygons with intersection %s\n",
|
||||
m_grid.has_intersecting_edges() ? "FAILED" : "SUCCEEDED");
|
||||
#if 0
|
||||
if (m_grid.has_intersecting_edges()) {
|
||||
// EdgeGrid fails to produce valid signed distance function for self-intersecting polygons.
|
||||
m_support_polygons_rotated = simplify_polygons(*m_support_polygons);
|
||||
m_support_polygons = &m_support_polygons_rotated;
|
||||
m_grid.set_bbox(bbox);
|
||||
m_grid.create(*m_support_polygons, grid_resolution);
|
||||
// assert(! m_grid.has_intersecting_edges());
|
||||
printf("SupportGridPattern: fixing polygons with intersection %s\n",
|
||||
m_grid.has_intersecting_edges() ? "FAILED" : "SUCCEEDED");
|
||||
}
|
||||
#endif
|
||||
m_grid.calculate_sdf();
|
||||
#endif // SUPPORT_USE_AGG_RASTERIZER
|
||||
break;
|
||||
}
|
||||
|
||||
case smsSnug:
|
||||
default:
|
||||
// nothing to prepare
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
m_grid.calculate_sdf();
|
||||
#endif // SUPPORT_USE_AGG_RASTERIZER
|
||||
}
|
||||
|
||||
// Extract polygons from the grid, offsetted by offset_in_grid,
|
||||
|
@ -770,97 +786,104 @@ public:
|
|||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef SUPPORT_USE_AGG_RASTERIZER
|
||||
Polygons support_polygons_simplified = contours_simplified(m_grid_size, m_pixel_size, m_bbox.min, m_grid2, offset_in_grid, fill_holes);
|
||||
#else // SUPPORT_USE_AGG_RASTERIZER
|
||||
// Generate islands, so each island may be tested for overlap with island_samples.
|
||||
assert(std::abs(2 * offset_in_grid) < m_grid.resolution());
|
||||
Polygons support_polygons_simplified = m_grid.contours_simplified(offset_in_grid, fill_holes);
|
||||
#endif // SUPPORT_USE_AGG_RASTERIZER
|
||||
switch (m_style) {
|
||||
case smsGrid:
|
||||
{
|
||||
#ifdef SUPPORT_USE_AGG_RASTERIZER
|
||||
Polygons support_polygons_simplified = contours_simplified(m_grid_size, m_pixel_size, m_bbox.min, m_grid2, offset_in_grid, fill_holes);
|
||||
#else // SUPPORT_USE_AGG_RASTERIZER
|
||||
// Generate islands, so each island may be tested for overlap with island_samples.
|
||||
assert(std::abs(2 * offset_in_grid) < m_grid.resolution());
|
||||
Polygons support_polygons_simplified = m_grid.contours_simplified(offset_in_grid, fill_holes);
|
||||
#endif // SUPPORT_USE_AGG_RASTERIZER
|
||||
|
||||
ExPolygons islands = diff_ex(support_polygons_simplified, *m_trimming_polygons, false);
|
||||
ExPolygons islands = diff_ex(support_polygons_simplified, *m_trimming_polygons, false);
|
||||
|
||||
// Extract polygons, which contain some of the island_samples.
|
||||
Polygons out;
|
||||
#if 0
|
||||
out = to_polygons(std::move(islands));
|
||||
#else
|
||||
// Extract polygons, which contain some of the island_samples.
|
||||
Polygons out;
|
||||
|
||||
// Sample a single point per input support polygon, keep it as a reference to maintain corresponding
|
||||
// polygons if ever these polygons get split into parts by the trimming polygons.
|
||||
// As offset_in_grid may be negative, m_support_polygons may stick slightly outside of islands.
|
||||
// Trim ti with islands.
|
||||
Points samples = island_samples(
|
||||
offset_in_grid > 0 ?
|
||||
// Expanding, thus m_support_polygons are all inside islands.
|
||||
union_ex(*m_support_polygons) :
|
||||
// Shrinking, thus m_support_polygons may be trimmed a tiny bit by islands.
|
||||
intersection_ex(*m_support_polygons, to_polygons(islands)));
|
||||
// Sample a single point per input support polygon, keep it as a reference to maintain corresponding
|
||||
// polygons if ever these polygons get split into parts by the trimming polygons.
|
||||
// As offset_in_grid may be negative, m_support_polygons may stick slightly outside of islands.
|
||||
// Trim ti with islands.
|
||||
Points samples = island_samples(
|
||||
offset_in_grid > 0 ?
|
||||
// Expanding, thus m_support_polygons are all inside islands.
|
||||
union_ex(*m_support_polygons) :
|
||||
// Shrinking, thus m_support_polygons may be trimmed a tiny bit by islands.
|
||||
intersection_ex(*m_support_polygons, to_polygons(islands)));
|
||||
|
||||
std::vector<std::pair<Point,bool>> samples_inside;
|
||||
for (ExPolygon &island : islands) {
|
||||
BoundingBox bbox = get_extents(island.contour);
|
||||
// Samples are sorted lexicographically.
|
||||
auto it_lower = std::lower_bound(samples.begin(), samples.end(), Point(bbox.min - Point(1, 1)));
|
||||
auto it_upper = std::upper_bound(samples.begin(), samples.end(), Point(bbox.max + Point(1, 1)));
|
||||
samples_inside.clear();
|
||||
for (auto it = it_lower; it != it_upper; ++ it)
|
||||
if (bbox.contains(*it))
|
||||
samples_inside.push_back(std::make_pair(*it, false));
|
||||
if (! samples_inside.empty()) {
|
||||
// For all samples_inside count the boundary crossing.
|
||||
for (size_t i_contour = 0; i_contour <= island.holes.size(); ++ i_contour) {
|
||||
Polygon &contour = (i_contour == 0) ? island.contour : island.holes[i_contour - 1];
|
||||
Points::const_iterator i = contour.points.begin();
|
||||
Points::const_iterator j = contour.points.end() - 1;
|
||||
for (; i != contour.points.end(); j = i ++) {
|
||||
//FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well.
|
||||
// Does the ray with y == point(1) intersect this line segment?
|
||||
for (auto &sample_inside : samples_inside) {
|
||||
if (((*i)(1) > sample_inside.first(1)) != ((*j)(1) > sample_inside.first(1))) {
|
||||
double x1 = (double)sample_inside.first(0);
|
||||
double x2 = (double)(*i)(0) + (double)((*j)(0) - (*i)(0)) * (double)(sample_inside.first(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1));
|
||||
if (x1 < x2)
|
||||
sample_inside.second = !sample_inside.second;
|
||||
std::vector<std::pair<Point,bool>> samples_inside;
|
||||
for (ExPolygon &island : islands) {
|
||||
BoundingBox bbox = get_extents(island.contour);
|
||||
// Samples are sorted lexicographically.
|
||||
auto it_lower = std::lower_bound(samples.begin(), samples.end(), Point(bbox.min - Point(1, 1)));
|
||||
auto it_upper = std::upper_bound(samples.begin(), samples.end(), Point(bbox.max + Point(1, 1)));
|
||||
samples_inside.clear();
|
||||
for (auto it = it_lower; it != it_upper; ++ it)
|
||||
if (bbox.contains(*it))
|
||||
samples_inside.push_back(std::make_pair(*it, false));
|
||||
if (! samples_inside.empty()) {
|
||||
// For all samples_inside count the boundary crossing.
|
||||
for (size_t i_contour = 0; i_contour <= island.holes.size(); ++ i_contour) {
|
||||
Polygon &contour = (i_contour == 0) ? island.contour : island.holes[i_contour - 1];
|
||||
Points::const_iterator i = contour.points.begin();
|
||||
Points::const_iterator j = contour.points.end() - 1;
|
||||
for (; i != contour.points.end(); j = i ++) {
|
||||
//FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well.
|
||||
// Does the ray with y == point(1) intersect this line segment?
|
||||
for (auto &sample_inside : samples_inside) {
|
||||
if (((*i)(1) > sample_inside.first(1)) != ((*j)(1) > sample_inside.first(1))) {
|
||||
double x1 = (double)sample_inside.first(0);
|
||||
double x2 = (double)(*i)(0) + (double)((*j)(0) - (*i)(0)) * (double)(sample_inside.first(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1));
|
||||
if (x1 < x2)
|
||||
sample_inside.second = !sample_inside.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If any of the sample is inside this island, add this island to the output.
|
||||
for (auto &sample_inside : samples_inside)
|
||||
if (sample_inside.second) {
|
||||
polygons_append(out, std::move(island));
|
||||
island.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If any of the sample is inside this island, add this island to the output.
|
||||
for (auto &sample_inside : samples_inside)
|
||||
if (sample_inside.second) {
|
||||
polygons_append(out, std::move(island));
|
||||
island.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
BoundingBox bbox = get_extents(*m_trimming_polygons);
|
||||
if (! islands.empty())
|
||||
bbox.merge(get_extents(islands));
|
||||
if (!out.empty())
|
||||
bbox.merge(get_extents(out));
|
||||
if (!support_polygons_simplified.empty())
|
||||
bbox.merge(get_extents(support_polygons_simplified));
|
||||
SVG svg(debug_out_path("extract_support_from_grid_trimmed-%s-%d-%d-%lf.svg", step_name, iRun, layer_id, print_z).c_str(), bbox);
|
||||
svg.draw(union_ex(support_polygons_simplified), "gray", 0.25f);
|
||||
svg.draw(islands, "red", 0.5f);
|
||||
svg.draw(union_ex(out), "green", 0.5f);
|
||||
svg.draw(union_ex(*m_support_polygons), "blue", 0.5f);
|
||||
svg.draw_outline(islands, "red", "red", scale_(0.05));
|
||||
svg.draw_outline(union_ex(out), "green", "green", scale_(0.05));
|
||||
svg.draw_outline(union_ex(*m_support_polygons), "blue", "blue", scale_(0.05));
|
||||
for (const Point &pt : samples)
|
||||
svg.draw(pt, "black", coord_t(scale_(0.15)));
|
||||
svg.Close();
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
|
||||
if (m_support_angle != 0.)
|
||||
polygons_rotate(out, m_support_angle);
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
BoundingBox bbox = get_extents(*m_trimming_polygons);
|
||||
if (! islands.empty())
|
||||
bbox.merge(get_extents(islands));
|
||||
if (!out.empty())
|
||||
bbox.merge(get_extents(out));
|
||||
if (!support_polygons_simplified.empty())
|
||||
bbox.merge(get_extents(support_polygons_simplified));
|
||||
SVG svg(debug_out_path("extract_support_from_grid_trimmed-%s-%d-%d-%lf.svg", step_name, iRun, layer_id, print_z).c_str(), bbox);
|
||||
svg.draw(union_ex(support_polygons_simplified), "gray", 0.25f);
|
||||
svg.draw(islands, "red", 0.5f);
|
||||
svg.draw(union_ex(out), "green", 0.5f);
|
||||
svg.draw(union_ex(*m_support_polygons), "blue", 0.5f);
|
||||
svg.draw_outline(islands, "red", "red", scale_(0.05));
|
||||
svg.draw_outline(union_ex(out), "green", "green", scale_(0.05));
|
||||
svg.draw_outline(union_ex(*m_support_polygons), "blue", "blue", scale_(0.05));
|
||||
for (const Point &pt : samples)
|
||||
svg.draw(pt, "black", coord_t(scale_(0.15)));
|
||||
svg.Close();
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
|
||||
if (m_support_angle != 0.)
|
||||
polygons_rotate(out, m_support_angle);
|
||||
return out;
|
||||
case smsSnug:
|
||||
// Just close the gaps.
|
||||
float thr = scaled<float>(0.5);
|
||||
return smooth_outward(offset(offset_ex(*m_support_polygons, thr), - thr), thr);
|
||||
}
|
||||
assert(false);
|
||||
return Polygons();
|
||||
}
|
||||
|
||||
#if defined(SLIC3R_DEBUG) && ! defined(SUPPORT_USE_AGG_RASTERIZER)
|
||||
|
@ -1096,6 +1119,7 @@ private:
|
|||
return pts;
|
||||
}
|
||||
|
||||
SupportMaterialStyle m_style;
|
||||
const Polygons *m_support_polygons;
|
||||
const Polygons *m_trimming_polygons;
|
||||
Polygons m_support_polygons_rotated;
|
||||
|
@ -1525,7 +1549,7 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
|
|||
ClipperLib::jtRound,
|
||||
// round mitter limit
|
||||
scale_(0.05)),
|
||||
slices_margin_cached);
|
||||
slices_margin.polygons);
|
||||
}
|
||||
#else
|
||||
diff_polygons = diff(diff_polygons, slices_margin.polygons);
|
||||
|
|
|
@ -278,7 +278,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto");
|
||||
bool have_support_interface = config->opt_int("support_material_interface_layers") > 0;
|
||||
bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0;
|
||||
for (auto el : { "support_material_pattern", "support_material_with_sheath",
|
||||
for (auto el : { "support_material_style", "support_material_pattern", "support_material_with_sheath",
|
||||
"support_material_spacing", "support_material_angle",
|
||||
"support_material_interface_pattern", "support_material_interface_layers",
|
||||
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
|
||||
|
|
|
@ -387,7 +387,7 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
|
|||
Update();
|
||||
}
|
||||
|
||||
void Control::SetLayersTimes(const std::vector<float>& layers_times)
|
||||
void Control::SetLayersTimes(const std::vector<float>& layers_times, float total_time)
|
||||
{
|
||||
m_layers_times.clear();
|
||||
if (layers_times.empty())
|
||||
|
@ -405,11 +405,18 @@ void Control::SetLayersTimes(const std::vector<float>& layers_times)
|
|||
m_layers_values = m_values;
|
||||
sort(m_layers_values.begin(), m_layers_values.end());
|
||||
m_layers_values.erase(unique(m_layers_values.begin(), m_layers_values.end()), m_layers_values.end());
|
||||
|
||||
// When whipe tower is used to the end of print, there is one layer which is not marked in layers_times
|
||||
// So, add this value from the total print time value
|
||||
if (m_layers_values.size() != m_layers_times.size())
|
||||
for (size_t i = m_layers_times.size(); i < m_layers_values.size(); i++)
|
||||
m_layers_times.push_back(total_time);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::SetLayersTimes(const std::vector<double>& layers_times)
|
||||
{
|
||||
m_is_smart_wipe_tower = false;
|
||||
m_layers_times = layers_times;
|
||||
for (size_t i = 1; i < m_layers_times.size(); i++)
|
||||
m_layers_times[i] += m_layers_times[i - 1];
|
||||
|
@ -652,7 +659,7 @@ void Control::draw_tick_on_mouse_position(wxDC& dc)
|
|||
}
|
||||
}
|
||||
|
||||
static std::string short_and_splitted_time(const std::string& time)
|
||||
static wxString short_and_splitted_time(const std::string& time)
|
||||
{
|
||||
// Parse the dhms time format.
|
||||
int days = 0;
|
||||
|
@ -690,7 +697,7 @@ static std::string short_and_splitted_time(const std::string& time)
|
|||
}
|
||||
else
|
||||
::sprintf(buffer, "%ds", seconds);
|
||||
return buffer;
|
||||
return wxString::FromUTF8(buffer);
|
||||
}
|
||||
|
||||
wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer*/) const
|
||||
|
@ -712,9 +719,13 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
|
|||
auto get_layer_number = [this](int value) {
|
||||
double layer_print_z = m_values[is_wipe_tower_layer(value) ? std::max<int>(value - 1, 0) : value];
|
||||
auto it = std::lower_bound(m_layers_values.begin(), m_layers_values.end(), layer_print_z - epsilon());
|
||||
if (it == m_layers_values.end())
|
||||
return -1;
|
||||
return int(it - m_layers_values.begin());
|
||||
if (it == m_layers_values.end()) {
|
||||
it = std::lower_bound(m_values.begin(), m_values.end(), layer_print_z - epsilon());
|
||||
if (it == m_values.end())
|
||||
return size_t(-1);
|
||||
return m_layers_values.size();
|
||||
}
|
||||
return size_t(it - m_layers_values.begin());
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
|
@ -730,8 +741,8 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
|
|||
else {
|
||||
if (label_type == ltEstimatedTime) {
|
||||
if (m_is_smart_wipe_tower) {
|
||||
int layer_number = get_layer_number(value);
|
||||
return layer_number < 0 ? "" : short_and_splitted_time(get_time_dhms(m_layers_times[layer_number]));
|
||||
size_t layer_number = get_layer_number(value);
|
||||
return layer_number == size_t(-1) ? "" : short_and_splitted_time(get_time_dhms(m_layers_times[layer_number]));
|
||||
}
|
||||
return value < m_layers_times.size() ? short_and_splitted_time(get_time_dhms(m_layers_times[value])) : "";
|
||||
}
|
||||
|
@ -741,7 +752,7 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
|
|||
if (label_type == ltHeight)
|
||||
return str;
|
||||
if (label_type == ltHeightWithLayer) {
|
||||
size_t layer_number = m_is_smart_wipe_tower ? (size_t)get_layer_number(value) : (m_values.empty() ? value : value + 1);
|
||||
size_t layer_number = m_is_smart_wipe_tower ? get_layer_number(value) : (m_values.empty() ? value : value + 1);
|
||||
return format_wxstr("%1%\n(%2%)", str, layer_number);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ public:
|
|||
|
||||
Info GetTicksValues() const;
|
||||
void SetTicksValues(const Info &custom_gcode_per_print_z);
|
||||
void SetLayersTimes(const std::vector<float>& layers_times);
|
||||
void SetLayersTimes(const std::vector<float>& layers_times, float total_time);
|
||||
void SetLayersTimes(const std::vector<double>& layers_times);
|
||||
|
||||
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
|
||||
|
|
|
@ -1224,6 +1224,8 @@ boost::any& Choice::get_value()
|
|||
m_value = static_cast<SupportMaterialPattern>(ret_enum);
|
||||
else if (m_opt_id.compare("support_material_interface_pattern") == 0)
|
||||
m_value = static_cast<SupportMaterialInterfacePattern>(ret_enum);
|
||||
else if (m_opt_id.compare("support_material_style") == 0)
|
||||
m_value = static_cast<SupportMaterialStyle>(ret_enum);
|
||||
else if (m_opt_id.compare("seam_position") == 0)
|
||||
m_value = static_cast<SeamPosition>(ret_enum);
|
||||
else if (m_opt_id.compare("host_type") == 0)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <boost/algorithm/string/split.hpp>
|
||||
#endif // ENABLE_GCODE_WINDOW
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
|
@ -3150,7 +3151,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
const Path& path = buffer->paths[path_id];
|
||||
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
|
||||
const Path::Sub_Path& sub_path = path.sub_paths[sub_path_id];
|
||||
if (m_sequential_view.current.last <= sub_path.first.s_id || sub_path.last.s_id <= m_sequential_view.current.first)
|
||||
if (m_sequential_view.current.last < sub_path.first.s_id || sub_path.last.s_id < m_sequential_view.current.first)
|
||||
continue;
|
||||
|
||||
Color color;
|
||||
|
|
|
@ -198,6 +198,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
|||
config.set_key_value(opt_key, new ConfigOptionEnum<SupportMaterialPattern>(boost::any_cast<SupportMaterialPattern>(value)));
|
||||
else if (opt_key.compare("support_material_interface_pattern") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<SupportMaterialInterfacePattern>(boost::any_cast<SupportMaterialInterfacePattern>(value)));
|
||||
else if (opt_key.compare("support_material_style") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<SupportMaterialStyle>(boost::any_cast<SupportMaterialStyle>(value)));
|
||||
else if (opt_key.compare("seam_position") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<SeamPosition>(boost::any_cast<SeamPosition>(value)));
|
||||
else if (opt_key.compare("host_type") == 0)
|
||||
|
|
|
@ -690,8 +690,8 @@ bool GUI_App::init_opengl()
|
|||
void GUI_App::init_app_config()
|
||||
{
|
||||
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
|
||||
SetAppName(SLIC3R_APP_KEY);
|
||||
// SetAppName(SLIC3R_APP_KEY "-beta");
|
||||
// SetAppName(SLIC3R_APP_KEY);
|
||||
SetAppName(SLIC3R_APP_KEY "-beta");
|
||||
// SetAppDisplayName(SLIC3R_APP_NAME);
|
||||
|
||||
// Set the Slic3r data directory at the Slic3r XS module.
|
||||
|
|
|
@ -50,7 +50,7 @@ static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF =
|
|||
{ L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } },
|
||||
{ L("Infill") , { "fill_density", "fill_pattern" } },
|
||||
{ L("Support material") , { "support_material", "support_material_auto", "support_material_threshold",
|
||||
"support_material_pattern", "support_material_interface_pattern", "support_material_buildplate_only",
|
||||
"support_material_pattern", "support_material_pattern", "support_material_interface_pattern", "support_material_buildplate_only",
|
||||
"support_material_spacing" } },
|
||||
{ L("Wipe options") , { "wipe_into_infill", "wipe_into_objects" } }
|
||||
};
|
||||
|
|
|
@ -639,8 +639,10 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
|
|||
m_layers_slider->SetDrawMode(sla_print_technology, sequential_print);
|
||||
if (sla_print_technology)
|
||||
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times);
|
||||
else
|
||||
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes.front().layers_times);
|
||||
else {
|
||||
auto print_mode_stat = m_gcode_result->time_statistics.modes.front();
|
||||
m_layers_slider->SetLayersTimes(print_mode_stat.layers_times, print_mode_stat.time);
|
||||
}
|
||||
|
||||
// Suggest the auto color change, if model looks like sign
|
||||
if (m_layers_slider->IsNewPrint())
|
||||
|
|
|
@ -525,7 +525,13 @@ void MainFrame::init_tabpanel()
|
|||
m_tabpanel->Hide();
|
||||
m_settings_dialog.set_tabpanel(m_tabpanel);
|
||||
|
||||
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) {
|
||||
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
Tab* old_tab = dynamic_cast<Tab*>(m_tabpanel->GetPage(e.GetOldSelection()));
|
||||
if (old_tab)
|
||||
old_tab->validate_custom_gcodes();
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
wxWindow* panel = m_tabpanel->GetCurrentPage();
|
||||
Tab* tab = dynamic_cast<Tab*>(panel);
|
||||
|
||||
|
@ -544,19 +550,6 @@ void MainFrame::init_tabpanel()
|
|||
select_tab(size_t(0)); // select Plater
|
||||
});
|
||||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, [this](wxBookCtrlEvent& evt) {
|
||||
wxWindow* panel = m_tabpanel->GetCurrentPage();
|
||||
if (panel != nullptr) {
|
||||
Tab* tab = dynamic_cast<Tab*>(panel);
|
||||
if (tab != nullptr)
|
||||
tab->validate_custom_gcodes();
|
||||
// if (tab != nullptr && !tab->validate_custom_gcodes())
|
||||
// evt.Veto();
|
||||
}
|
||||
});
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
m_plater = new Plater(this, this);
|
||||
m_plater->Hide();
|
||||
|
||||
|
@ -1158,7 +1151,7 @@ void MainFrame::init_menubar_as_editor()
|
|||
|
||||
editMenu->AppendSeparator();
|
||||
append_menu_item(editMenu, wxID_ANY, _L("Searc&h") + "\tCtrl+F",
|
||||
_L("Search in settings"), [this](wxCommandEvent&) { m_plater->search(/*m_tabpanel->GetCurrentPage() == */m_plater->IsShown()); },
|
||||
_L("Search in settings"), [this](wxCommandEvent&) { m_plater->search(m_plater->IsShown()); },
|
||||
"search", nullptr, []() {return true; }, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -535,7 +535,7 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index
|
|||
m_opt_map.emplace(opt_id, pair);
|
||||
|
||||
if (m_use_custom_ctrl) // fill group and category values just for options from Settings Tab
|
||||
wxGetApp().sidebar().get_searcher().add_key(opt_id, title, this->config_category());
|
||||
wxGetApp().sidebar().get_searcher().add_key(opt_id, static_cast<Preset::Type>(this->config_type()), title, this->config_category());
|
||||
|
||||
return Option(*m_config->def()->get(opt_key), opt_id);
|
||||
}
|
||||
|
|
|
@ -224,10 +224,11 @@ public:
|
|||
ConfigOptionsGroup( wxWindow* parent) :
|
||||
OptionsGroup(parent, wxEmptyString, true, nullptr) {}
|
||||
|
||||
const std::string& config_category() const throw() { return m_config_category; }
|
||||
const wxString& config_category() const throw() { return m_config_category; }
|
||||
int config_type() const throw() { return m_config_type; }
|
||||
const t_opt_map& opt_map() const throw() { return m_opt_map; }
|
||||
|
||||
void set_config_category(const std::string &category) { this->m_config_category = category; }
|
||||
void set_config_category_and_type(const wxString &category, int type) { this->m_config_category = category; this->m_config_type = type; }
|
||||
void set_config(DynamicPrintConfig* config) { m_config = config; m_modelconfig = nullptr; }
|
||||
Option get_option(const std::string& opt_key, int opt_index = -1);
|
||||
Line create_single_option_line(const std::string& title, const wxString& path = wxEmptyString, int idx = -1) /*const*/{
|
||||
|
@ -274,7 +275,8 @@ private:
|
|||
// If the config is modelconfig, then ModelConfig::touch() has to be called after value change.
|
||||
ModelConfig* m_modelconfig { nullptr };
|
||||
t_opt_map m_opt_map;
|
||||
std::string m_config_category;
|
||||
wxString m_config_category;
|
||||
int m_config_type;
|
||||
|
||||
// Change an option on m_config, possibly call ModelConfig::touch().
|
||||
void change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
|
||||
|
|
|
@ -992,7 +992,7 @@ void Sidebar::search()
|
|||
void Sidebar::jump_to_option(size_t selected)
|
||||
{
|
||||
const Search::Option& opt = p->searcher.get_option(selected);
|
||||
wxGetApp().get_tab(opt.type)->activate_option(boost::nowide::narrow(opt.opt_key), boost::nowide::narrow(opt.category));
|
||||
wxGetApp().get_tab(opt.type)->activate_option(opt.opt_key(), boost::nowide::narrow(opt.category));
|
||||
|
||||
// Switch to the Settings NotePad
|
||||
// wxGetApp().mainframe->select_tab();
|
||||
|
@ -5858,6 +5858,8 @@ void Plater::paste_from_clipboard()
|
|||
void Plater::search(bool plater_is_active)
|
||||
{
|
||||
if (plater_is_active) {
|
||||
if (is_preview_shown())
|
||||
return;
|
||||
// plater should be focused for correct navigation inside search window
|
||||
this->SetFocus();
|
||||
|
||||
|
|
|
@ -63,24 +63,29 @@ void change_opt_key(std::string& opt_key, DynamicPrintConfig* config, int& cnt)
|
|||
opt_key += "#" + std::to_string(0);
|
||||
}
|
||||
|
||||
static std::string get_key(const std::string& opt_key, Preset::Type type)
|
||||
{
|
||||
return std::to_string(int(type)) + ";" + opt_key;
|
||||
}
|
||||
|
||||
void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type type, ConfigOptionMode mode)
|
||||
{
|
||||
auto emplace = [this, type](const std::string opt_key, const wxString& label)
|
||||
auto emplace = [this, type](const std::string key, const wxString& label)
|
||||
{
|
||||
const GroupAndCategory& gc = groups_and_categories[opt_key];
|
||||
const GroupAndCategory& gc = groups_and_categories[key];
|
||||
if (gc.group.IsEmpty() || gc.category.IsEmpty())
|
||||
return;
|
||||
|
||||
wxString suffix;
|
||||
wxString suffix_local;
|
||||
if (gc.category == "Machine limits") {
|
||||
suffix = opt_key.back()=='1' ? L("Stealth") : L("Normal");
|
||||
suffix = key.back()=='1' ? L("Stealth") : L("Normal");
|
||||
suffix_local = " " + _(suffix);
|
||||
suffix = " " + suffix;
|
||||
}
|
||||
|
||||
if (!label.IsEmpty())
|
||||
options.emplace_back(Option{ boost::nowide::widen(opt_key), type,
|
||||
options.emplace_back(Option{ boost::nowide::widen(key), type,
|
||||
(label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(),
|
||||
gc.group.ToStdWstring(), _(gc.group).ToStdWstring(),
|
||||
gc.category.ToStdWstring(), GUI::Tab::translate_category(gc.category, type).ToStdWstring() });
|
||||
|
@ -108,12 +113,13 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
|
|||
|
||||
wxString label = opt.full_label.empty() ? opt.label : opt.full_label;
|
||||
|
||||
std::string key = get_key(opt_key, type);
|
||||
if (cnt == 0)
|
||||
emplace(opt_key, label);
|
||||
emplace(key, label);
|
||||
else
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
// ! It's very important to use "#". opt_key#n is a real option key used in GroupAndCategory
|
||||
emplace(opt_key + "#" + std::to_string(i), label);
|
||||
emplace(key + "#" + std::to_string(i), label);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,10 +243,10 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
|
|||
int score2;
|
||||
matches.clear();
|
||||
fuzzy_match(wsearch, label, score, matches);
|
||||
if (fuzzy_match(wsearch, opt.opt_key, score2, matches2) && score2 > score) {
|
||||
if (fuzzy_match(wsearch, opt.key, score2, matches2) && score2 > score) {
|
||||
for (fts::pos_type &pos : matches2)
|
||||
pos += label.size() + 1;
|
||||
label += L"(" + opt.opt_key + L")";
|
||||
label += L"(" + opt.key + L")";
|
||||
append(matches, matches2);
|
||||
score = score2;
|
||||
}
|
||||
|
@ -318,9 +324,9 @@ const Option& OptionsSearcher::get_option(size_t pos_in_filter) const
|
|||
return options[found[pos_in_filter].option_idx];
|
||||
}
|
||||
|
||||
const Option& OptionsSearcher::get_option(const std::string& opt_key) const
|
||||
const Option& OptionsSearcher::get_option(const std::string& opt_key, Preset::Type type) const
|
||||
{
|
||||
auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key) }));
|
||||
auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(get_key(opt_key, type)) }));
|
||||
assert(it != options.end());
|
||||
|
||||
return options[it - options.begin()];
|
||||
|
@ -342,7 +348,7 @@ static Option create_option(const std::string& opt_key, const wxString& label, P
|
|||
category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1);
|
||||
}
|
||||
|
||||
return Option{ boost::nowide::widen(opt_key), type,
|
||||
return Option{ boost::nowide::widen(get_key(opt_key, type)), type,
|
||||
(label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(),
|
||||
gc.group.ToStdWstring(), _(gc.group).ToStdWstring(),
|
||||
gc.category.ToStdWstring(), GUI::Tab::translate_category(category, type).ToStdWstring() };
|
||||
|
@ -350,15 +356,16 @@ static Option create_option(const std::string& opt_key, const wxString& label, P
|
|||
|
||||
Option OptionsSearcher::get_option(const std::string& opt_key, const wxString& label, Preset::Type type) const
|
||||
{
|
||||
auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key) }));
|
||||
if(it->opt_key == boost::nowide::widen(opt_key))
|
||||
std::string key = get_key(opt_key, type);
|
||||
auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(key) }));
|
||||
if(it->key == boost::nowide::widen(key))
|
||||
return options[it - options.begin()];
|
||||
if (groups_and_categories.find(opt_key) == groups_and_categories.end()) {
|
||||
size_t pos = opt_key.find('#');
|
||||
if (groups_and_categories.find(key) == groups_and_categories.end()) {
|
||||
size_t pos = key.find('#');
|
||||
if (pos == std::string::npos)
|
||||
return options[it - options.begin()];
|
||||
|
||||
std::string zero_opt_key = opt_key.substr(0, pos + 1) + "0";
|
||||
std::string zero_opt_key = key.substr(0, pos + 1) + "0";
|
||||
|
||||
if(groups_and_categories.find(zero_opt_key) == groups_and_categories.end())
|
||||
return options[it - options.begin()];
|
||||
|
@ -366,16 +373,16 @@ Option OptionsSearcher::get_option(const std::string& opt_key, const wxString& l
|
|||
return create_option(opt_key, label, type, groups_and_categories.at(zero_opt_key));
|
||||
}
|
||||
|
||||
const GroupAndCategory& gc = groups_and_categories.at(opt_key);
|
||||
const GroupAndCategory& gc = groups_and_categories.at(key);
|
||||
if (gc.group.IsEmpty() || gc.category.IsEmpty())
|
||||
return options[it - options.begin()];
|
||||
|
||||
return create_option(opt_key, label, type, gc);
|
||||
}
|
||||
|
||||
void OptionsSearcher::add_key(const std::string& opt_key, const wxString& group, const wxString& category)
|
||||
void OptionsSearcher::add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category)
|
||||
{
|
||||
groups_and_categories[opt_key] = GroupAndCategory{group, category};
|
||||
groups_and_categories[get_key(opt_key, type)] = GroupAndCategory{group, category};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,11 +38,11 @@ struct GroupAndCategory {
|
|||
|
||||
struct Option {
|
||||
// bool operator<(const Option& other) const { return other.label > this->label; }
|
||||
bool operator<(const Option& other) const { return other.opt_key > this->opt_key; }
|
||||
bool operator<(const Option& other) const { return other.key > this->key; }
|
||||
|
||||
// Fuzzy matching works at a character level. Thus matching with wide characters is a safer bet than with short characters,
|
||||
// though for some languages (Chinese?) it may not work correctly.
|
||||
std::wstring opt_key;
|
||||
std::wstring key;
|
||||
Preset::Type type {Preset::TYPE_INVALID};
|
||||
std::wstring label;
|
||||
std::wstring label_local;
|
||||
|
@ -50,6 +50,8 @@ struct Option {
|
|||
std::wstring group_local;
|
||||
std::wstring category;
|
||||
std::wstring category_local;
|
||||
|
||||
std::string opt_key() const { return boost::nowide::narrow(key).substr(2); }
|
||||
};
|
||||
|
||||
struct FoundOption {
|
||||
|
@ -110,13 +112,13 @@ public:
|
|||
bool search();
|
||||
bool search(const std::string& search, bool force = false);
|
||||
|
||||
void add_key(const std::string& opt_key, const wxString& group, const wxString& category);
|
||||
void add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category);
|
||||
|
||||
size_t size() const { return found_size(); }
|
||||
|
||||
const FoundOption& operator[](const size_t pos) const noexcept { return found[pos]; }
|
||||
const Option& get_option(size_t pos_in_filter) const;
|
||||
const Option& get_option(const std::string& opt_key) const;
|
||||
const Option& get_option(const std::string& opt_key, Preset::Type type) const;
|
||||
Option get_option(const std::string& opt_key, const wxString& label, Preset::Type type) const;
|
||||
|
||||
const std::vector<FoundOption>& found_options() { return found; }
|
||||
|
@ -125,10 +127,11 @@ public:
|
|||
|
||||
void set_printer_technology(PrinterTechnology pt) { printer_technology = pt; }
|
||||
|
||||
void sort_options_by_opt_key() {
|
||||
void sort_options_by_key() {
|
||||
std::sort(options.begin(), options.end(), [](const Option& o1, const Option& o2) {
|
||||
return o1.opt_key < o2.opt_key; });
|
||||
return o1.key < o2.key; });
|
||||
}
|
||||
void sort_options_by_label() { sort_options(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1506,6 +1506,7 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("raft_expansion");
|
||||
|
||||
optgroup = page->new_optgroup(L("Options for support material and raft"));
|
||||
optgroup->append_single_option_line("support_material_style", category_path + "style");
|
||||
optgroup->append_single_option_line("support_material_contact_distance", category_path + "contact-z-distance");
|
||||
optgroup->append_single_option_line("support_material_bottom_contact_distance", category_path + "contact-z-distance");
|
||||
optgroup->append_single_option_line("support_material_pattern", category_path + "pattern");
|
||||
|
@ -1737,7 +1738,7 @@ bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode)
|
|||
}
|
||||
|
||||
static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, const t_config_option_key& opt_key, const boost::any& value) {
|
||||
Tab::validate_custom_gcode(opt_group->title, boost::any_cast<std::string>(value));
|
||||
tab->validate_custom_gcodes_was_shown = !Tab::validate_custom_gcode(opt_group->title, boost::any_cast<std::string>(value));
|
||||
tab->update_dirty();
|
||||
tab->on_value_change(opt_key, value);
|
||||
}
|
||||
|
@ -3801,8 +3802,8 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
|
|||
{
|
||||
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
|
||||
const Search::GroupAndCategory& gc = searcher.get_group_and_category("bed_shape");
|
||||
searcher.add_key("bed_custom_texture", gc.group, gc.category);
|
||||
searcher.add_key("bed_custom_model", gc.group, gc.category);
|
||||
searcher.add_key("bed_custom_texture", m_type, gc.group, gc.category);
|
||||
searcher.add_key("bed_custom_model", m_type, gc.group, gc.category);
|
||||
}
|
||||
|
||||
return sizer;
|
||||
|
@ -3836,27 +3837,18 @@ bool Tab::validate_custom_gcodes()
|
|||
if (m_active_page->title() != L("Custom G-code"))
|
||||
return true;
|
||||
|
||||
// When we switch Settings tab after editing of the custom g-code, then warning message could ba already shown after KillFocus event
|
||||
// and then it's no need to show it again
|
||||
if (validate_custom_gcodes_was_shown) {
|
||||
validate_custom_gcodes_was_shown = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
for (auto opt_group : m_active_page->m_optgroups) {
|
||||
assert(opt_group->opt_map().size() == 1);
|
||||
std::string key = opt_group->opt_map().begin()->first;
|
||||
std::string value = boost::any_cast<std::string>(opt_group->get_value(key));
|
||||
std::string config_value = m_type == Preset::TYPE_FILAMENT ? m_config->opt_string(key, 0u) : m_config->opt_string(key);
|
||||
valid &= validate_custom_gcode(opt_group->title, value);
|
||||
Field* field = opt_group->get_field(key);
|
||||
TextCtrl* text_ctrl = dynamic_cast<TextCtrl*>(field);
|
||||
if (text_ctrl != nullptr && text_ctrl->m_on_change != nullptr && !text_ctrl->m_disable_change_event) {
|
||||
Slic3r::GUI::t_change callback = opt_group->m_on_change;
|
||||
// temporary disable the opt_group->m_on_change callback to avoid multiple validations
|
||||
opt_group->m_on_change = nullptr;
|
||||
text_ctrl->m_on_change(key, value);
|
||||
// restore the opt_group->m_on_change callback
|
||||
opt_group->m_on_change = callback;
|
||||
|
||||
update_dirty();
|
||||
on_value_change(key, value);
|
||||
}
|
||||
|
||||
valid &= validate_custom_gcode(opt_group->title, boost::any_cast<std::string>(opt_group->get_value(key)));
|
||||
if (!valid)
|
||||
break;
|
||||
}
|
||||
|
@ -4043,7 +4035,6 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
|
|||
{
|
||||
//! config_ have to be "right"
|
||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, title, m_config, true);
|
||||
optgroup->set_config_category(m_title.ToStdString());
|
||||
if (noncommon_label_width >= 0)
|
||||
optgroup->label_width = noncommon_label_width;
|
||||
|
||||
|
@ -4052,6 +4043,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
|
|||
#else
|
||||
auto tab = parent()->GetParent();// GetParent();
|
||||
#endif
|
||||
optgroup->set_config_category_and_type(m_title, static_cast<Tab*>(tab)->type());
|
||||
optgroup->m_on_change = [tab](t_config_option_key opt_key, boost::any value) {
|
||||
//! This function will be called from OptionGroup.
|
||||
//! Using of CallAfter is redundant.
|
||||
|
|
|
@ -351,6 +351,7 @@ public:
|
|||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
static bool validate_custom_gcode(const wxString& title, const std::string& gcode);
|
||||
bool validate_custom_gcodes();
|
||||
bool validate_custom_gcodes_was_shown { false };
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
protected:
|
||||
|
|
|
@ -833,10 +833,10 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
|
|||
(*btn)->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { show_info_line(Action::Undef); e.Skip(); });
|
||||
};
|
||||
|
||||
const PresetCollection& printers = wxGetApp().preset_bundle->printers;
|
||||
if (dependent_presets && (type == dependent_presets->type() ?
|
||||
const PresetCollection* switched_presets = type == Preset::TYPE_INVALID ? nullptr : wxGetApp().get_tab(type)->get_presets();
|
||||
if (dependent_presets && switched_presets && (type == dependent_presets->type() ?
|
||||
dependent_presets->get_edited_preset().printer_technology() == dependent_presets->find_preset(new_selected_preset)->printer_technology() :
|
||||
printers.get_edited_preset().printer_technology() == printers.find_preset(new_selected_preset)->printer_technology()))
|
||||
switched_presets->get_edited_preset().printer_technology() == switched_presets->find_preset(new_selected_preset)->printer_technology()))
|
||||
add_btn(&m_transfer_btn, m_move_btn_id, "paste_menu", Action::Transfer, _L("Transfer"));
|
||||
add_btn(&m_discard_btn, m_continue_btn_id, dependent_presets ? "switch_presets" : "exit", Action::Discard, _L("Discard"), false);
|
||||
add_btn(&m_save_btn, m_save_btn_id, "save", Action::Save, _L("Save"));
|
||||
|
@ -1185,7 +1185,7 @@ void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent
|
|||
void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* presets_)
|
||||
{
|
||||
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
|
||||
searcher.sort_options_by_opt_key();
|
||||
searcher.sort_options_by_key();
|
||||
|
||||
// list of the presets with unsaved changes
|
||||
std::vector<PresetCollection*> presets_list;
|
||||
|
@ -1227,8 +1227,8 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
|
|||
}
|
||||
|
||||
for (const std::string& opt_key : dirty_options) {
|
||||
const Search::Option& option = searcher.get_option(opt_key);
|
||||
if (option.opt_key != boost::nowide::widen(opt_key)) {
|
||||
const Search::Option& option = searcher.get_option(opt_key, type);
|
||||
if (option.opt_key() != opt_key) {
|
||||
// When founded option isn't the correct one.
|
||||
// It can be for dirty_options: "default_print_profile", "printer_model", "printer_settings_id",
|
||||
// because of they don't exist in searcher
|
||||
|
@ -1239,6 +1239,9 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
|
|||
get_string_value(opt_key, old_config), get_string_value(opt_key, new_config), category_icon_map.at(option.category));
|
||||
}
|
||||
}
|
||||
|
||||
// Revert sort of searcher back
|
||||
searcher.sort_options_by_label();
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
|
@ -1546,7 +1549,7 @@ void DiffPresetDialog::update_presets(Preset::Type type)
|
|||
void DiffPresetDialog::update_tree()
|
||||
{
|
||||
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
|
||||
searcher.sort_options_by_opt_key();
|
||||
searcher.sort_options_by_key();
|
||||
|
||||
m_tree->Clear();
|
||||
wxString bottom_info = "";
|
||||
|
@ -1617,7 +1620,7 @@ void DiffPresetDialog::update_tree()
|
|||
wxString right_val = get_string_value(opt_key, right_congig);
|
||||
|
||||
Search::Option option = searcher.get_option(opt_key, get_full_label(opt_key, left_config), type);
|
||||
if (option.opt_key != boost::nowide::widen(opt_key)) {
|
||||
if (option.opt_key() != opt_key) {
|
||||
// temporary solution, just for testing
|
||||
m_tree->Append(opt_key, type, _L("Undef category"), _L("Undef group"), opt_key, left_val, right_val, "question");
|
||||
// When founded option isn't the correct one.
|
||||
|
@ -1642,6 +1645,9 @@ void DiffPresetDialog::update_tree()
|
|||
Fit();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
// Revert sort of searcher back
|
||||
searcher.sort_options_by_label();
|
||||
}
|
||||
|
||||
void DiffPresetDialog::on_dpi_changed(const wxRect&)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
set(SLIC3R_APP_NAME "PrusaSlicer")
|
||||
set(SLIC3R_APP_KEY "PrusaSlicer")
|
||||
set(SLIC3R_VERSION "2.3.0")
|
||||
set(SLIC3R_VERSION "2.4.0-alpha0")
|
||||
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
||||
set(SLIC3R_RC_VERSION "2,3,0,0")
|
||||
set(SLIC3R_RC_VERSION_DOTS "2.3.0.0")
|
||||
set(SLIC3R_RC_VERSION "2,4,0,0")
|
||||
set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")
|
||||
|
|
Loading…
Add table
Reference in a new issue