polyholes are rotated on each layer.

supermerill/SuperSlicer#1396
This commit is contained in:
supermerill 2021-08-22 20:50:37 +02:00
parent 201cf90b97
commit 37a6688174
6 changed files with 50 additions and 19 deletions

View File

@ -106,6 +106,7 @@ group:Modifying slices
line:Convert round vertical holes to polyholes
setting:label$_:hole_to_polyhole
setting:hole_to_polyhole_threshold
setting:hole_to_polyhole_twisted
end_line
group:Other
setting:clip_multipart_objects

View File

@ -597,6 +597,7 @@ const std::vector<std::string>& Preset::print_options()
"hole_size_threshold",
"hole_to_polyhole",
"hole_to_polyhole_threshold",
"hole_to_polyhole_twisted",
"threads",
// wipe tower
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging",

View File

@ -4440,13 +4440,21 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Polyhole detection margin");
def->category = OptionCategory::slicing;
def->tooltip = L("Maximum defection of a point to the estimated radius of the circle."
"\nAs cylinders are often exported as triangles of varying size, points may not be on the circle circumference."
" This setting allows you some leway to broaden the detection."
"\nIn mm or in % of the radius.");
"\nAs cylinders are often exported as triangles of varying size, points may not be on the circle circumference."
" This setting allows you some leway to broaden the detection."
"\nIn mm or in % of the radius.");
def->sidetext = L("mm or %");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(0.01, false));
def = this->add("hole_to_polyhole_twisted", coBool);
def->label = L("Twisting");
def->full_label = L("Polyhole twist");
def->category = OptionCategory::slicing;
def->tooltip = L("Rotate the polyhole every layer.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("z_offset", coFloat);
def->label = L("Z offset");
def->category = OptionCategory::general;
@ -5596,6 +5604,7 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
"hole_size_threshold",
"hole_to_polyhole",
"hole_to_polyhole_threshold",
"hole_to_polyhole_twisted",
"z_step",
"milling_cutter",
"milling_diameter",

View File

@ -798,6 +798,7 @@ public:
ConfigOptionFloatOrPercent infill_anchor_max;
ConfigOptionBool hole_to_polyhole;
ConfigOptionFloatOrPercent hole_to_polyhole_threshold;
ConfigOptionBool hole_to_polyhole_twisted;
ConfigOptionInt infill_extruder;
ConfigOptionFloatOrPercent infill_extrusion_width;
ConfigOptionInt infill_every_layers;
@ -914,6 +915,7 @@ protected:
OPT_PTR(infill_anchor_max);
OPT_PTR(hole_to_polyhole);
OPT_PTR(hole_to_polyhole_threshold);
OPT_PTR(hole_to_polyhole_twisted);
OPT_PTR(infill_extruder);
OPT_PTR(infill_extrusion_width);
OPT_PTR(infill_every_layers);

View File

@ -151,25 +151,41 @@ namespace Slic3r {
}
Polygon create_polyhole(const Point center, const coord_t radius, const coord_t nozzle_diameter)
Polygons create_polyholes(const Point center, const coord_t radius, const coord_t nozzle_diameter, bool multiple)
{
// n = max(round(2 * d), 3); // for 0.4mm nozzle
size_t nb_polygons = (int)std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter)));
size_t nb_edges = (int)std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter)));
// cylinder(h = h, r = d / cos (180 / n), $fn = n);
Points pts;
const float new_radius = radius / std::cos(PI / nb_polygons);
for (int i = 0; i < nb_polygons; ++i) {
float angle = (PI * 2 * i) / nb_polygons;
pts.emplace_back(center.x() + new_radius * cos(angle), center.y() + new_radius * sin(angle));
//create x polyholes by rotation if multiple
int nb_polyhole = 1;
float rotation = 0;
if (multiple) {
nb_polyhole = 5;
rotation = 2 * float(PI) / (nb_edges * nb_polyhole);
}
return Polygon{ pts };
Polygons list;
for (int i_poly = 0; i_poly < nb_polyhole; i_poly++)
list.emplace_back();
for (int i_poly = 0; i_poly < nb_polyhole; i_poly++) {
Polygon& pts = (((i_poly % 2) == 0) ? list[i_poly / 2] : list[(nb_polyhole + 1) / 2 + i_poly / 2]);
const float new_radius = radius / float(std::cos(PI / nb_edges));
for (int i_edge = 0; i_edge < nb_edges; ++i_edge) {
float angle = rotation * i_poly + (float(PI) * 2 * i_edge) / nb_edges;
pts.points.emplace_back(center.x() + new_radius * cos(angle), center.y() + new_radius * sin(angle));
}
pts.make_clockwise();
}
//alternate
return list;
}
void PrintObject::_transform_hole_to_polyholes()
{
// get all circular holes for each layer
// the id is center-diameter-extruderid
std::vector<std::vector<std::pair<std::tuple<Point, float, int, coord_t>, Polygon*>>> layerid2center;
//the tuple is Point center; float diameter_max; int extruder_id; coord_t max_variation; bool twist;
std::vector<std::vector<std::pair<std::tuple<Point, float, int, coord_t, bool>, Polygon*>>> layerid2center;
for (size_t i = 0; i < this->m_layers.size(); i++) layerid2center.emplace_back();
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
@ -196,9 +212,10 @@ namespace Slic3r {
}
// SCALED_EPSILON was a bit too harsh. Now using a config, as some may want some harsh setting and some don't.
coord_t max_variation = std::max(SCALED_EPSILON, scale_(this->m_layers[layer_idx]->m_regions[region_idx]->region()->config().hole_to_polyhole_threshold.get_abs_value(unscaled(diameter_sum / hole.points.size()))));
bool twist = this->m_layers[layer_idx]->m_regions[region_idx]->region()->config().hole_to_polyhole_twisted.value;
if (diameter_max - diameter_min < max_variation * 2) {
layerid2center[layer_idx].emplace_back(
std::tuple<Point, float, int, coord_t>{center, diameter_max, layer->m_regions[region_idx]->region()->config().perimeter_extruder.value, max_variation}, & hole);
std::tuple<Point, float, int, coord_t, bool>{center, diameter_max, layer->m_regions[region_idx]->region()->config().perimeter_extruder.value, max_variation, twist}, & hole);
}
}
}
@ -209,7 +226,7 @@ namespace Slic3r {
}
});
//sort holes per center-diameter
std::map<std::tuple<Point, float, int, coord_t>, std::vector<std::pair<Polygon*, int>>> id2layerz2hole;
std::map<std::tuple<Point, float, int, coord_t, bool>, std::vector<std::pair<Polygon*, int>>> id2layerz2hole;
//search & find hole that span at least X layers
const size_t min_nb_layers = 2;
@ -217,7 +234,7 @@ namespace Slic3r {
for (size_t layer_idx = 0; layer_idx < this->m_layers.size(); ++layer_idx) {
for (size_t hole_idx = 0; hole_idx < layerid2center[layer_idx].size(); ++hole_idx) {
//get all other same polygons
std::tuple<Point, float, int, coord_t>& id = layerid2center[layer_idx][hole_idx].first;
std::tuple<Point, float, int, coord_t, bool>& id = layerid2center[layer_idx][hole_idx].first;
float max_z = layers()[layer_idx]->print_z;
std::vector<std::pair<Polygon*, int>> holes;
holes.emplace_back(layerid2center[layer_idx][hole_idx].second, layer_idx);
@ -225,7 +242,7 @@ namespace Slic3r {
if (layers()[search_layer_idx]->print_z - layers()[search_layer_idx]->height - max_z > EPSILON) break;
//search an other polygon with same id
for (size_t search_hole_idx = 0; search_hole_idx < layerid2center[search_layer_idx].size(); ++search_hole_idx) {
std::tuple<Point, float, int, coord_t>& search_id = layerid2center[search_layer_idx][search_hole_idx].first;
std::tuple<Point, float, int, coord_t, bool>& search_id = layerid2center[search_layer_idx][search_hole_idx].first;
if (std::get<2>(id) == std::get<2>(search_id)
&& std::get<0>(id).distance_to(std::get<0>(search_id)) < std::get<3>(id)
&& std::abs(std::get<1>(id) - std::get<1>(search_id)) < std::get<3>(id)
@ -246,9 +263,9 @@ namespace Slic3r {
}
//create a polyhole per id and replace holes points by it.
for (auto entry : id2layerz2hole) {
Polygon polyhole = create_polyhole(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)));
polyhole.make_clockwise();
Polygons polyholes = create_polyholes(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)), std::get<4>(entry.first));
for (auto& poly_to_replace : entry.second) {
Polygon polyhole = polyholes[poly_to_replace.second % polyholes.size()];
//search the clone in layers->slices
for (ExPolygon& explo_slice : m_layers[poly_to_replace.second]->lslices) {
for (Polygon& poly_slice : explo_slice.holes) {

View File

@ -430,7 +430,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
for (auto el : { "solid_fill_pattern", "infill_connection_solid" })
toggle_field(el, has_solid_infill); // should be top_solid_layers") > 1 || bottom_solid_layers") > 1
toggle_field("hole_to_polyhole_threshold", config->opt_bool("hole_to_polyhole"));
for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" })
toggle_field(el, config->opt_bool("hole_to_polyhole"));
bool have_default_acceleration = config->option<ConfigOptionFloatOrPercent>("default_acceleration")->value > 0;
for (auto el : { "perimeter_acceleration", "infill_acceleration",