mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-16 00:01:47 +08:00
new feature: smooth curve
* it create more points to smooth rough curves, do hide polygons in the final print. also, create a new tab in the print settings for the ones related to the mesh.
This commit is contained in:
parent
e23f4020af
commit
8ba954d2aa
@ -172,7 +172,8 @@ private:
|
||||
void generate_support_material();
|
||||
|
||||
void _slice(const std::vector<coordf_t> &layer_height_profile);
|
||||
void _offsetHoles(float hole_delta, LayerRegion *layerm);
|
||||
void _offset_holes(float hole_delta, LayerRegion *layerm);
|
||||
void _smooth_curves(LayerRegion *layerm);
|
||||
std::string _fix_slicing_errors();
|
||||
void _simplify_slices(double distance);
|
||||
void _make_perimeters();
|
||||
|
@ -375,7 +375,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("elefant_foot_compensation", coFloat);
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer compensation");
|
||||
def->category = L("Advanced");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("The first layer will be grown / shrunk in the XY plane by the configured value "
|
||||
"to compensate for the 1st layer squish aka an Elephant Foot effect. (should be negative = inwards)");
|
||||
def->sidetext = L("mm");
|
||||
@ -2132,6 +2132,35 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(15, false);
|
||||
|
||||
def = this->add("curve_smoothing_angle", coFloat);
|
||||
def->label = L("Min angle");
|
||||
def->full_label = L("Curve smoothing minimum angle");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("Minimum angle at a vertex to enable smoothing"
|
||||
" (trying to create a curve around the vertex). "
|
||||
"180 : nothing will be smooth, 0 : all angles will be smoothen.");
|
||||
def->sidetext = L("°");
|
||||
def->cli = "curve-smoothing-angle=f";
|
||||
def->min = 0;
|
||||
def->max = 180;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("curve_smoothing_precision", coFloat);
|
||||
def->label = L("Precision");
|
||||
def->full_label = L("Curve smoothing precision");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("These parameter allow the slicer to smooth the angles in each layer. "
|
||||
"The precision will be at least the new precision of the curve. Set to 0 to deactivate."
|
||||
"\nNote: as it use the polygon's edges and only work in the 2D planes, "
|
||||
"you must have a very clean or hand-made 3D model."
|
||||
"\nIt's really only useful to smoothen functional models or very wide angles.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->cli = "curve-smoothing-precision=f";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("solid_infill_below_area", coFloat);
|
||||
def->label = L("Solid infill threshold area");
|
||||
def->category = L("Infill");
|
||||
@ -2258,7 +2287,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("model_precision", coFloat);
|
||||
def->label = L("Model rounding precision");
|
||||
def->full_label = L("Model rounding precision");
|
||||
def->category = L("Advanced");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("This is the rounding error of the input object."
|
||||
" It's used to align points that should be in the same line."
|
||||
" Put 0 to disable.");
|
||||
@ -2860,7 +2889,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("xy_size_compensation", coFloat);
|
||||
def->label = L("All layers");
|
||||
def->full_label = L("XY size compensation");
|
||||
def->category = L("Advanced");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("The object will be grown/shrunk in the XY plane by the configured value "
|
||||
"(negative = inwards, positive = outwards). This might be useful "
|
||||
"for fine-tuning sizes.");
|
||||
@ -2872,7 +2901,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("hole_size_compensation", coFloat);
|
||||
def->label = L("Holes");
|
||||
def->full_label = L("XY holes compensation");
|
||||
def->category = L("Advanced");
|
||||
def->category = L("Slicing");
|
||||
def->tooltip = L("The convex holes will be grown / shrunk in the XY plane by the configured value"
|
||||
" (negative = inwards, positive = outwards, should be negative as the holes are always a bit smaller irl)."
|
||||
" This might be useful for fine-tuning hole sizes.");
|
||||
|
@ -561,6 +561,8 @@ public:
|
||||
ConfigOptionEnum<InfillPattern> bottom_fill_pattern;
|
||||
ConfigOptionFloatOrPercent bridged_infill_margin;
|
||||
ConfigOptionFloat bridge_speed;
|
||||
ConfigOptionFloat curve_smoothing_precision;
|
||||
ConfigOptionFloat curve_smoothing_angle;
|
||||
ConfigOptionBool ensure_vertical_shell_thickness;
|
||||
ConfigOptionBool enforce_full_fill_volume;
|
||||
ConfigOptionFloatOrPercent external_infill_margin;
|
||||
@ -620,6 +622,8 @@ protected:
|
||||
OPT_PTR(bottom_fill_pattern);
|
||||
OPT_PTR(bridged_infill_margin);
|
||||
OPT_PTR(bridge_speed);
|
||||
OPT_PTR(curve_smoothing_precision);
|
||||
OPT_PTR(curve_smoothing_angle);
|
||||
OPT_PTR(ensure_vertical_shell_thickness);
|
||||
OPT_PTR(enforce_full_fill_volume);
|
||||
OPT_PTR(external_infill_margin);
|
||||
|
@ -1882,7 +1882,8 @@ end:
|
||||
LayerRegion *layerm = layer->m_regions.front();
|
||||
layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stPosInternal | stDensSparse);
|
||||
}
|
||||
_offsetHoles(hole_delta, layer->regions().front());
|
||||
_offset_holes(hole_delta, layer->regions().front());
|
||||
_smooth_curves(layer->regions().front());
|
||||
} else if (scale || clip || hole_delta != 0.f) {
|
||||
// Multiple regions, growing, shrinking or just clipping one region by the other.
|
||||
// When clipping the regions, priority is given to the first regions.
|
||||
@ -1899,7 +1900,8 @@ end:
|
||||
// Collect the already processed regions to trim the to be processed regions.
|
||||
polygons_append(processed, slices);
|
||||
layerm->slices.set(std::move(slices), stPosInternal | stDensSparse);
|
||||
_offsetHoles(hole_delta, layerm);
|
||||
_offset_holes(hole_delta, layerm);
|
||||
_smooth_curves(layerm);
|
||||
}
|
||||
}
|
||||
// Merge all regions' slices to get islands, chain them by a shortest path.
|
||||
@ -1910,9 +1912,8 @@ end:
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
|
||||
}
|
||||
|
||||
void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) {
|
||||
void PrintObject::_offset_holes(float hole_delta, LayerRegion *layerm) {
|
||||
if (hole_delta != 0.f) {
|
||||
std::cout << "offset_hole z="<<layerm->layer()->id()<<"\n";
|
||||
ExPolygons polys = to_expolygons(std::move(layerm->slices.surfaces));
|
||||
ExPolygons new_polys;
|
||||
for (const ExPolygon &ex_poly : polys) {
|
||||
@ -1950,6 +1951,96 @@ void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) {
|
||||
}
|
||||
}
|
||||
|
||||
/// max angle: you ahve to be lwer than that to divide it. PI => all accepted
|
||||
/// min angle: don't smooth sharp angles! 0 => all accepted
|
||||
Polygon _smooth_curve(Polygon &p, double max_angle, double min_angle, coord_t max_dist){
|
||||
if (p.size() < 4) return p;
|
||||
Polygon pout;
|
||||
//duplicate points to simplify the loop
|
||||
p.points.insert(p.points.end(), p.points.begin(), p.points.begin() + 3);
|
||||
for (size_t idx = 1; idx<p.size() - 2; idx++){
|
||||
pout.points.push_back(p[idx]);
|
||||
double angle1 = p[idx].ccw_angle(p.points[idx - 1], p.points[idx + 1]);
|
||||
if (angle1 > PI) angle1 = 2 * PI - angle1;
|
||||
double angle2 = p[idx + 1].ccw_angle(p.points[idx], p.points[idx + 2]);
|
||||
if (angle2 > PI) angle2 = 2 * PI - angle2;
|
||||
if (angle1 < min_angle && angle2 < min_angle) continue;
|
||||
if (angle1 > max_angle && angle2 > max_angle) continue;
|
||||
// add points, but how many?
|
||||
coordf_t dist = p[idx].distance_to(p[idx + 1]);
|
||||
int nb_add = dist / max_dist;
|
||||
if (max_angle < PI) {
|
||||
int nb_add_per_angle = std::max((PI - angle1) / (PI - max_angle), (PI - angle2) / (PI - max_angle));
|
||||
nb_add = std::min(nb_add, nb_add_per_angle);
|
||||
}
|
||||
if (nb_add == 0) continue;
|
||||
|
||||
//création des points de controles
|
||||
Vec2d vec_ab = (p[idx] - p[idx - 1]).cast<double>();
|
||||
Vec2d vec_bc = (p[idx + 1] - p[idx]).cast<double>();
|
||||
Vec2d vec_cb = (p[idx] - p[idx + 1]).cast<double>();
|
||||
Vec2d vec_dc = (p[idx + 1] - p[idx + 2]).cast<double>();
|
||||
vec_ab.normalize();
|
||||
vec_bc.normalize();
|
||||
vec_cb.normalize();
|
||||
vec_dc.normalize();
|
||||
Vec2d vec_b_tang = vec_ab + vec_bc;
|
||||
vec_b_tang.normalize();
|
||||
//should be 0.55 / 1.414 = ~0.39 to create a true circle from a square (90°)
|
||||
// it's ~0.36 for exagon (120°)
|
||||
// it's ~0.34 for octogon (135°)
|
||||
vec_b_tang *= dist * (0.31 + 0.12 * (1-(angle1 / PI)));
|
||||
Vec2d vec_c_tang = vec_dc + vec_cb;
|
||||
vec_c_tang.normalize();
|
||||
vec_c_tang *= dist * (0.31 + 0.12 * (1 - (angle1 / PI)));
|
||||
Point bp = p[idx] + ((angle1 < min_angle) ? vec_bc.cast<coord_t>() : vec_b_tang.cast<coord_t>());
|
||||
Point cp = p[idx + 1] + ((angle2 < min_angle) ? vec_cb.cast<coord_t>() : vec_c_tang.cast<coord_t>());
|
||||
for (int idx_np = 0; idx_np < nb_add; idx_np++){
|
||||
const float percent_np = (idx_np + 1) / (float)(nb_add + 1);
|
||||
const float inv_percent_np = 1 - percent_np;
|
||||
pout.points.emplace_back();
|
||||
Point &new_p = pout.points.back();
|
||||
const float coeff0 = inv_percent_np * inv_percent_np * inv_percent_np;
|
||||
const float coeff1 = percent_np * inv_percent_np * inv_percent_np;
|
||||
const float coeff2 = percent_np * percent_np * inv_percent_np;
|
||||
const float coeff3 = percent_np * percent_np * percent_np;
|
||||
new_p.x() = (p[idx].x() * coeff0)
|
||||
+ (3 * bp.x() * coeff1)
|
||||
+ (3 * cp.x() * coeff2)
|
||||
+ (p[idx + 1].x() * coeff3);
|
||||
new_p.y() = (p[idx].y() * coeff0)
|
||||
+ (3 * bp.y() * coeff1)
|
||||
+ (3 * cp.y() * coeff2)
|
||||
+ (p[idx + 1].y() * coeff3);
|
||||
}
|
||||
|
||||
}
|
||||
return pout;
|
||||
}
|
||||
|
||||
void PrintObject::_smooth_curves(LayerRegion *layerm) {
|
||||
|
||||
if (layerm->region()->config().curve_smoothing_precision.value > 0.f) {
|
||||
ExPolygons new_polys;
|
||||
for (const Surface &srf : layerm->slices.surfaces) {
|
||||
const ExPolygon &ex_poly = srf.expolygon;
|
||||
ExPolygon new_ex_poly(ex_poly);
|
||||
new_ex_poly.contour = _smooth_curve(new_ex_poly.contour, PI,
|
||||
layerm->region()->config().curve_smoothing_angle.value*PI / 180.0,
|
||||
scale_(layerm->region()->config().curve_smoothing_precision.value));
|
||||
for (Polygon &phole : new_ex_poly.holes){
|
||||
phole.reverse(); // make_counter_clockwise();
|
||||
phole = _smooth_curve(phole, PI,
|
||||
layerm->region()->config().curve_smoothing_angle.value*PI / 180.0,
|
||||
scale_(layerm->region()->config().curve_smoothing_precision.value));
|
||||
phole.reverse(); // make_clockwise();
|
||||
}
|
||||
new_polys.push_back(new_ex_poly);
|
||||
}
|
||||
layerm->slices.set(std::move(new_polys), stPosInternal | stDensSparse);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier)
|
||||
{
|
||||
std::vector<const ModelVolume*> volumes;
|
||||
|
@ -403,6 +403,8 @@ const std::vector<std::string>& Preset::print_options()
|
||||
, "thin_walls_min_width"
|
||||
, "thin_walls_overlap"
|
||||
, "model_precision"
|
||||
, "curve_smoothing_precision"
|
||||
, "curve_smoothing_angle"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -945,10 +945,10 @@ void Tab::update_frequently_changed_parameters()
|
||||
|
||||
void TabPrint::build()
|
||||
{
|
||||
m_presets = &m_preset_bundle->prints;
|
||||
m_presets = &m_preset_bundle->prints;
|
||||
Line line{ "", "" };
|
||||
load_initial_data();
|
||||
|
||||
auto page = add_options_page(_(L("Layers and perimeters")), "layers.png");
|
||||
auto page = add_options_page(_(L("Layers and perimeters")), "layers.png");
|
||||
auto optgroup = page->new_optgroup(_(L("Layer height")));
|
||||
optgroup->append_single_option_line("layer_height");
|
||||
optgroup->append_single_option_line("first_layer_height");
|
||||
@ -958,8 +958,8 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("perimeters");
|
||||
optgroup->append_single_option_line("spiral_vase");
|
||||
|
||||
Line line { "", "" };
|
||||
line.full_width = 1;
|
||||
line = { "", "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
return description_line_widget(parent, &m_recommended_thin_wall_thickness_description_line);
|
||||
};
|
||||
@ -1147,6 +1147,26 @@ void TabPrint::build()
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
optgroup->append_single_option_line("interface_shells");
|
||||
|
||||
|
||||
page = add_options_page(_(L("Slicing")), "layers.png");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Filtering")));
|
||||
optgroup->append_single_option_line("slice_closing_radius");
|
||||
optgroup->append_single_option_line("resolution");
|
||||
optgroup->append_single_option_line("model_precision");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Modifying")));
|
||||
line = { _(L("Curve smoothing")), "" };
|
||||
line.append_option(optgroup->get_option("curve_smoothing_precision"));
|
||||
line.append_option(optgroup->get_option("curve_smoothing_angle"));
|
||||
optgroup->append_line(line);
|
||||
line = { _(L("XY compensation")), "" };
|
||||
line.append_option(optgroup->get_option("xy_size_compensation"));
|
||||
line.append_option(optgroup->get_option("elefant_foot_compensation"));
|
||||
line.append_option(optgroup->get_option("hole_size_compensation"));
|
||||
optgroup->append_line(line);
|
||||
|
||||
|
||||
page = add_options_page(_(L("Advanced")), "wrench.png");
|
||||
optgroup = page->new_optgroup(_(L("Extrusion width")));
|
||||
optgroup->append_single_option_line("extrusion_width");
|
||||
@ -1165,21 +1185,10 @@ void TabPrint::build()
|
||||
line = { _(L("Bridge flow ratio")), "" };
|
||||
line.append_option(optgroup->get_option("bridge_flow_ratio"));
|
||||
line.append_option(optgroup->get_option("over_bridge_flow_ratio"));
|
||||
optgroup->append_line(line);
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Slicing")));
|
||||
optgroup->append_single_option_line("slice_closing_radius");
|
||||
optgroup->append_single_option_line("resolution");
|
||||
line = { _(L("XY compensation")), "" };
|
||||
line.append_option(optgroup->get_option("xy_size_compensation"));
|
||||
line.append_option(optgroup->get_option("elefant_foot_compensation"));
|
||||
line.append_option(optgroup->get_option("hole_size_compensation"));
|
||||
optgroup->append_line(line);
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Other")));
|
||||
optgroup->append_single_option_line("clip_multipart_objects");
|
||||
optgroup->append_single_option_line("resolution");
|
||||
optgroup->append_single_option_line("model_precision");
|
||||
|
||||
page = add_options_page(_(L("Output options")), "page_white_go.png");
|
||||
optgroup = page->new_optgroup(_(L("Sequential printing")));
|
||||
|
Loading…
x
Reference in New Issue
Block a user