Polyholes!

slic3r/Sliç3r#3323
slic3r/Sliç3r#2438
prusa3d/PrusaSlicer#515
This commit is contained in:
supermerill 2019-11-01 22:10:17 +01:00
parent dbb6fbe9c3
commit a43b2b123d
7 changed files with 167 additions and 32 deletions

View File

@ -182,6 +182,7 @@ private:
void _slice(const std::vector<coordf_t> &layer_height_profile); void _slice(const std::vector<coordf_t> &layer_height_profile);
void _offset_holes(double hole_delta, LayerRegion *layerm); void _offset_holes(double hole_delta, LayerRegion *layerm);
void _transform_hole_to_polyholes();
void _smooth_curves(LayerRegion *layerm); void _smooth_curves(LayerRegion *layerm);
std::string _fix_slicing_errors(); std::string _fix_slicing_errors();
void _simplify_slices(double distance); void _simplify_slices(double distance);

View File

@ -1232,6 +1232,7 @@ void PrintConfigDef::init_fff_params()
"over the default layer height."); "over the default layer height.");
def->sidetext = L("mm or %"); def->sidetext = L("mm or %");
def->ratio_over = "layer_height"; def->ratio_over = "layer_height";
def->min = 0;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0.2, false)); def->set_default_value(new ConfigOptionFloatOrPercent(0.2, false));
@ -3011,6 +3012,16 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));
def = this->add("hole_to_polyhole", coBool);
def->label = L("Convert round holes to polyholes");
def->full_label = L("Convert round holes to polyholes");
def->category = L("Slicing");
def->tooltip = L("Search for almost-circular holes that span more than one layer and conert the geometry to polyholes."
" Use the nozzle size and the (biggest) diameter to compute the polyhole."
"\nSee http://hydraraptor.blogspot.com/2011/02/polyholes.html");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("z_offset", coFloat); def = this->add("z_offset", coFloat);
def->label = L("Z offset"); def->label = L("Z offset");
def->tooltip = L("This value will be added (or subtracted) from all the Z coordinates " def->tooltip = L("This value will be added (or subtracted) from all the Z coordinates "

View File

@ -598,6 +598,7 @@ public:
ConfigOptionBool gap_fill; ConfigOptionBool gap_fill;
ConfigOptionFloatOrPercent gap_fill_min_area; ConfigOptionFloatOrPercent gap_fill_min_area;
ConfigOptionFloat gap_fill_speed; ConfigOptionFloat gap_fill_speed;
ConfigOptionBool hole_to_polyhole;
ConfigOptionInt infill_extruder; ConfigOptionInt infill_extruder;
ConfigOptionFloatOrPercent infill_extrusion_width; ConfigOptionFloatOrPercent infill_extrusion_width;
ConfigOptionInt infill_every_layers; ConfigOptionInt infill_every_layers;
@ -667,6 +668,7 @@ protected:
OPT_PTR(gap_fill); OPT_PTR(gap_fill);
OPT_PTR(gap_fill_min_area); OPT_PTR(gap_fill_min_area);
OPT_PTR(gap_fill_speed); OPT_PTR(gap_fill_speed);
OPT_PTR(hole_to_polyhole);
OPT_PTR(infill_extruder); OPT_PTR(infill_extruder);
OPT_PTR(infill_extrusion_width); OPT_PTR(infill_extrusion_width);
OPT_PTR(infill_every_layers); OPT_PTR(infill_every_layers);

View File

@ -122,11 +122,127 @@ void PrintObject::slice()
// Simplify slices if required. // Simplify slices if required.
if (m_print->config().resolution) if (m_print->config().resolution)
this->_simplify_slices(scale_(this->print()->config().resolution)); this->_simplify_slices(scale_(this->print()->config().resolution));
//create polyholes
this->_transform_hole_to_polyholes();
if (m_layers.empty()) if (m_layers.empty())
throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n"); throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");
this->set_done(posSlice); this->set_done(posSlice);
} }
Polygon create_polyhole(const Point center, const coord_t diameter, const coord_t nozzle_diameter)
{
// n = max(round(2 * d), 3); // for 0.4mm nozzle
size_t nb_polygons = (int)std::max(3, (int)std::round(2.0 * unscaled(diameter) * 0.4 / unscaled(nozzle_diameter)));
// cylinder(h = h, r = (d / 2) / cos (180 / n), $fn = n);
Points pts;
const float rayon = (diameter / 1) / 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() + rayon * cos(angle), center.y() + rayon * sin(angle));
}
return Polygon{ pts };
}
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>, 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()),
//[this, layerid2center](const tbb::blocked_range<size_t>& range) {
//for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
for (size_t layer_idx = 0; layer_idx < this->m_layers.size(); ++layer_idx) {
m_print->throw_if_canceled();
Layer *layer = m_layers[layer_idx];
for (size_t region_idx = 0; region_idx < layer->m_regions.size(); ++region_idx)
{
if (layer->m_regions[region_idx]->region()->config().hole_to_polyhole) {
for (Surface &surf : layer->m_regions[region_idx]->m_slices.surfaces) {
for (Polygon &hole : surf.expolygon.holes) {
//test if convex (as it's clockwise bc it's a hole, we have to do the opposite)
if (hole.convex_points().empty() && hole.points.size() > 4) {
double center_x = 0, center_y = 0;
for (int i = 0; i < hole.points.size(); ++i) {
center_x += hole.points[i].x();
center_y += hole.points[i].y();
}
Point center{ center_x / hole.points.size(), center_y / hole.points.size() };
double diameter_min = std::numeric_limits<float>::max(), diameter_max = 0;
for (int i = 0; i < hole.points.size(); ++i) {
double dist = hole.points[i].distance_to_square(center);
diameter_min = std::min(diameter_min, dist);
diameter_max = std::max(diameter_max, dist);
}
diameter_min = std::sqrt(diameter_min);
diameter_max = std::sqrt(diameter_max);
if (diameter_max - diameter_min < SCALED_EPSILON) {
layerid2center[layer_idx].emplace_back(
std::tuple<Point, float, int>{center, diameter_max, layer->m_regions[region_idx]->region()->config().perimeter_extruder.value}, &hole);
}
}
}
}
}
}
// for layer->slices, it will be also replaced later.
}
//});
//sort holes per center-diameter
std::map<std::tuple<Point, float, int>,std::vector<std::pair<Polygon*,int>>> id2layerz2hole;
//search & find hole that span at least X layers
const size_t min_nb_layers = 2;
float max_layer_height = config().layer_height * 2;
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> &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);
for (size_t search_layer_idx = layer_idx + 1; search_layer_idx < this->m_layers.size(); ++search_layer_idx) {
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> &search_id = layerid2center[search_layer_idx][search_hole_idx].first;
if (std::get<0>(id).distance_to(std::get<0>(search_id)) < SCALED_EPSILON
&& std::abs(std::get<1>(id) - std::get<1>(search_id)) < SCALED_EPSILON
&& std::get<2>(id) == std::get<2>(search_id)) {
max_z = layers()[search_layer_idx]->print_z;
holes.emplace_back(layerid2center[search_layer_idx][search_hole_idx].second, search_layer_idx);
layerid2center[search_layer_idx].erase(layerid2center[search_layer_idx].begin() + search_hole_idx);
search_hole_idx--;
break;
}
}
}
if (holes.size() >= min_nb_layers) {
id2layerz2hole.emplace(std::move(id), std::move(holes));
}
}
}
//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();
for (auto &poly_to_replace : entry.second) {
//search the clone in layers->slices
for (ExPolygon &explo_slice : m_layers[poly_to_replace.second]->slices.expolygons) {
for (Polygon &poly_slice : explo_slice.holes) {
if (poly_slice.points == poly_to_replace.first->points) {
poly_slice.points = polyhole.points;
}
}
}
// copy
poly_to_replace.first->points = polyhole.points;
}
}
}
// 1) Merges typed region slices into stInternal type. // 1) Merges typed region slices into stInternal type.
// 2) Increases an "extra perimeters" counter at region slices where needed. // 2) Increases an "extra perimeters" counter at region slices where needed.
// 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal). // 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
@ -500,7 +616,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "support_material_contact_distance_top" || opt_key == "support_material_contact_distance_top"
|| opt_key == "support_material_contact_distance_bottom" || opt_key == "support_material_contact_distance_bottom"
|| opt_key == "xy_size_compensation" || opt_key == "xy_size_compensation"
|| opt_key == "hole_size_compensation") { || opt_key == "hole_size_compensation"
|| opt_key == "hole_to_polyhole") {
steps.emplace_back(posSlice); steps.emplace_back(posSlice);
} else if (opt_key == "support_material") { } else if (opt_key == "support_material") {
steps.emplace_back(posSupportMaterial); steps.emplace_back(posSupportMaterial);

View File

@ -47,7 +47,7 @@ SlicingParameters SlicingParameters::create_from_config(
coordf_t object_height, coordf_t object_height,
const std::vector<unsigned int> &object_extruders) const std::vector<unsigned int> &object_extruders)
{ {
coordf_t first_layer_height = (object_config.first_layer_height.value <= 0) ? coordf_t first_layer_height = (object_config.first_layer_height.get_abs_value(object_config.layer_height.value) <= 0) ?
object_config.layer_height.value : object_config.layer_height.value :
object_config.first_layer_height.get_abs_value(object_config.layer_height.value); object_config.first_layer_height.get_abs_value(object_config.layer_height.value);
// If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0, // If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0,

View File

@ -426,7 +426,9 @@ const std::vector<std::string>& Preset::print_options()
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio",
"clip_multipart_objects", "clip_multipart_objects",
"over_bridge_flow_ratio", "clip_multipart_objects", "enforce_full_fill_volume", "external_infill_margin", "bridged_infill_margin", "over_bridge_flow_ratio", "clip_multipart_objects", "enforce_full_fill_volume", "external_infill_margin", "bridged_infill_margin",
"elefant_foot_compensation", "xy_size_compensation", "hole_size_compensation", "threads", "resolution", "elefant_foot_compensation", "xy_size_compensation", "hole_size_compensation",
"hole_to_polyhole",
"threads", "resolution",
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging",
"single_extruder_multi_material_priming", "compatible_printers", "compatible_printers_condition", "inherits", "single_extruder_multi_material_priming", "compatible_printers", "compatible_printers_condition", "inherits",
"infill_dense", "infill_dense_algo", "infill_dense", "infill_dense_algo",

View File

@ -1109,6 +1109,8 @@ void TabPrint::build()
line.append_option(optgroup->get_option("hole_size_compensation")); line.append_option(optgroup->get_option("hole_size_compensation"));
optgroup->append_line(line); optgroup->append_line(line);
optgroup->append_single_option_line("hole_to_polyhole");
optgroup = page->new_optgroup(_(L("Other"))); optgroup = page->new_optgroup(_(L("Other")));
optgroup->append_single_option_line("clip_multipart_objects"); optgroup->append_single_option_line("clip_multipart_objects");