mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-01-30 23:48:44 +03:00
add max_bridge_length
This commit is contained in:
@@ -113,6 +113,47 @@ void Polyline::simplify(double tolerance)
|
|||||||
this->points = MultiPoint::douglas_peucker(this->points, tolerance);
|
this->points = MultiPoint::douglas_peucker(this->points, tolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//w28
|
||||||
|
Polylines Polyline::equally_spaced_lines(double distance) const
|
||||||
|
{
|
||||||
|
Polylines lines;
|
||||||
|
Polyline line;
|
||||||
|
line.append(this->first_point());
|
||||||
|
double len = 0;
|
||||||
|
|
||||||
|
for (Points::const_iterator it = this->points.begin() + 1; it != this->points.end(); ++it) {
|
||||||
|
Vec2d p1 = line.points.back().cast<double>();
|
||||||
|
Vec2d v = it->cast<double>() - p1;
|
||||||
|
double segment_length = v.norm();
|
||||||
|
len += segment_length;
|
||||||
|
if (len < distance)
|
||||||
|
continue;
|
||||||
|
if (len == distance) {
|
||||||
|
line.append(*it);
|
||||||
|
lines.emplace_back(line);
|
||||||
|
|
||||||
|
line.clear();
|
||||||
|
line.append(*it);
|
||||||
|
len = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double take = distance;
|
||||||
|
line.append((p1 + v * (take / v.norm())).cast<coord_t>());
|
||||||
|
lines.emplace_back(line);
|
||||||
|
|
||||||
|
line.clear();
|
||||||
|
line.append(lines.back().last_point());
|
||||||
|
--it;
|
||||||
|
len = -take;
|
||||||
|
}
|
||||||
|
if (line.size() == 1) {
|
||||||
|
line.append(this->last_point());
|
||||||
|
if (line.first_point() != line.last_point())
|
||||||
|
lines.emplace_back(line);
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// This method simplifies all *lines* contained in the supplied area
|
// This method simplifies all *lines* contained in the supplied area
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ public:
|
|||||||
|
|
||||||
using iterator = Points::iterator;
|
using iterator = Points::iterator;
|
||||||
using const_iterator = Points::const_iterator;
|
using const_iterator = Points::const_iterator;
|
||||||
|
//w28
|
||||||
|
Polylines equally_spaced_lines(double distance) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const Polyline &lhs, const Polyline &rhs) { return lhs.points == rhs.points; }
|
inline bool operator==(const Polyline &lhs, const Polyline &rhs) { return lhs.points == rhs.points; }
|
||||||
|
|||||||
@@ -489,6 +489,8 @@ static std::vector<std::string> s_Preset_print_options {
|
|||||||
,"elefant_foot_compensation_layers"
|
,"elefant_foot_compensation_layers"
|
||||||
//w27
|
//w27
|
||||||
,"precise_z_height"
|
,"precise_z_height"
|
||||||
|
//w28
|
||||||
|
,"max_bridge_length"
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<std::string> s_Preset_filament_options {
|
static std::vector<std::string> s_Preset_filament_options {
|
||||||
|
|||||||
@@ -868,6 +868,17 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionBool(true));
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
|
//w28
|
||||||
|
def = this->add("max_bridge_length", coFloat);
|
||||||
|
def->label = L("Max bridge length");
|
||||||
|
def->category = L("Support material");
|
||||||
|
def->tooltip = L("Max length of bridges that don't need support. Set it to 0 if you want all bridges to be supported, and set it to a "
|
||||||
|
"very large value if you don't want any bridges to be supported.");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(10));
|
||||||
|
|
||||||
def = this->add("duplicate_distance", coFloat);
|
def = this->add("duplicate_distance", coFloat);
|
||||||
def->label = L("Distance between copies");
|
def->label = L("Distance between copies");
|
||||||
def->tooltip = L("Distance used for the auto-arrange feature of the plater.");
|
def->tooltip = L("Distance used for the auto-arrange feature of the plater.");
|
||||||
|
|||||||
@@ -512,6 +512,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||||||
((ConfigOptionEnum<BrimType>, brim_type))
|
((ConfigOptionEnum<BrimType>, brim_type))
|
||||||
((ConfigOptionFloat, brim_width))
|
((ConfigOptionFloat, brim_width))
|
||||||
((ConfigOptionBool, dont_support_bridges))
|
((ConfigOptionBool, dont_support_bridges))
|
||||||
|
//w28
|
||||||
|
((ConfigOptionFloat, max_bridge_length))
|
||||||
((ConfigOptionFloat, elefant_foot_compensation))
|
((ConfigOptionFloat, elefant_foot_compensation))
|
||||||
//w26
|
//w26
|
||||||
((ConfigOptionInt, elefant_foot_compensation_layers))
|
((ConfigOptionInt, elefant_foot_compensation_layers))
|
||||||
|
|||||||
@@ -792,7 +792,9 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "raft_first_layer_density"
|
|| opt_key == "raft_first_layer_density"
|
||||||
|| opt_key == "raft_first_layer_expansion"
|
|| opt_key == "raft_first_layer_expansion"
|
||||||
|| opt_key == "dont_support_bridges"
|
|| opt_key == "dont_support_bridges"
|
||||||
|| opt_key == "first_layer_extrusion_width") {
|
|| opt_key == "first_layer_extrusion_width"
|
||||||
|
//w28
|
||||||
|
|| opt_key == "max_bridge_length") {
|
||||||
steps.emplace_back(posSupportMaterial);
|
steps.emplace_back(posSupportMaterial);
|
||||||
} else if (opt_key == "bottom_solid_layers") {
|
} else if (opt_key == "bottom_solid_layers") {
|
||||||
steps.emplace_back(posPrepareInfill);
|
steps.emplace_back(posPrepareInfill);
|
||||||
|
|||||||
@@ -120,6 +120,104 @@ void remove_bridges_from_contacts(
|
|||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//w28
|
||||||
|
void remove_bridges_from_contacts_select_area(
|
||||||
|
const PrintConfig &print_config, const Layer &lower_layer, const LayerRegion &layerm, float fw, Polygons &contact_polygons,const double max_bridge_length)
|
||||||
|
{
|
||||||
|
Polygons bridges;
|
||||||
|
{
|
||||||
|
Polygons lower_grown_slices =
|
||||||
|
expand(lower_layer.lslices,
|
||||||
|
// FIXME to mimic the decision in the perimeter generator, we should use half the external perimeter width.
|
||||||
|
0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm.region().config().perimeter_extruder - 1))),
|
||||||
|
SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||||
|
#if 0
|
||||||
|
Polylines overhang_perimeters = layerm.perimeters.as_polylines();
|
||||||
|
for (Polyline &polyline : overhang_perimeters)
|
||||||
|
polyline.points[0].x += 1;
|
||||||
|
overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
|
||||||
|
#else
|
||||||
|
Polylines overhang_perimeters = diff_pl(layerm.perimeters().as_polylines(), lower_grown_slices);
|
||||||
|
#endif
|
||||||
|
Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter);
|
||||||
|
const float w = float(std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing())) ;
|
||||||
|
for (Polyline &polyline : overhang_perimeters)
|
||||||
|
if (polyline.is_straight()) {
|
||||||
|
polyline.extend_start(fw);
|
||||||
|
polyline.extend_end(fw);
|
||||||
|
Point pts[2] = {polyline.first_point(), polyline.last_point()};
|
||||||
|
bool supported[2] = {false, false};
|
||||||
|
for (size_t i = 0; i < lower_layer.lslices.size() && !(supported[0] && supported[1]); ++i)
|
||||||
|
for (int j = 0; j < 2; ++j)
|
||||||
|
if (!supported[j] && lower_layer.lslices_ex[i].bbox.contains(pts[j]) && lower_layer.lslices[i].contains(pts[j]))
|
||||||
|
supported[j] = true;
|
||||||
|
if (supported[0] && supported[1]) {
|
||||||
|
Polylines lines;
|
||||||
|
if (polyline.length() > max_bridge_length + 10) {
|
||||||
|
// equally divide the polyline
|
||||||
|
float len = polyline.length() / ceil(polyline.length() / max_bridge_length);
|
||||||
|
lines = polyline.equally_spaced_lines(len);
|
||||||
|
for (auto &line : lines) {
|
||||||
|
line.clip_start(fw);
|
||||||
|
line.clip_end(fw);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
lines.push_back(polyline);
|
||||||
|
polygons_append(bridges, offset(lines, 0.5f * w + 10.f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bridges = union_(bridges);
|
||||||
|
|
||||||
|
for (const Surface &surface : layerm.fill_surfaces().surfaces)
|
||||||
|
if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) {
|
||||||
|
auto bbox = get_extents(surface.expolygon);
|
||||||
|
auto bbox_size = bbox.size();
|
||||||
|
if (bbox_size[0] < max_bridge_length && bbox_size[1] < max_bridge_length)
|
||||||
|
polygons_append(bridges, surface.expolygon);
|
||||||
|
else {
|
||||||
|
Polygons holes;
|
||||||
|
coord_t x0 = bbox.min.x();
|
||||||
|
coord_t x1 = bbox.max.x();
|
||||||
|
coord_t y0 = bbox.min.y();
|
||||||
|
coord_t y1 = bbox.max.y();
|
||||||
|
const int grid_lw = int(w );
|
||||||
|
Vec2f bridge_direction{cos(surface.bridge_angle), sin(surface.bridge_angle)};
|
||||||
|
if (fabs(bridge_direction(0)) >
|
||||||
|
fabs(bridge_direction(1))) {
|
||||||
|
int step = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length);
|
||||||
|
for (int x = x0 + step; x < x1; x += step) {
|
||||||
|
Polygon poly;
|
||||||
|
poly.points = {Point(x - grid_lw, y0), Point(x + grid_lw, y0), Point(x + grid_lw, y1), Point(x - grid_lw, y1)};
|
||||||
|
holes.emplace_back(poly);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int step = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length);
|
||||||
|
for (int y = y0 + step; y < y1; y += step) {
|
||||||
|
Polygon poly;
|
||||||
|
poly.points = {Point(x0, y - grid_lw), Point(x0, y + grid_lw), Point(x1, y + grid_lw), Point(x1, y - grid_lw)};
|
||||||
|
holes.emplace_back(poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto expoly = diff_ex(surface.expolygon, holes);
|
||||||
|
polygons_append(bridges, expoly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bridges = diff(bridges,
|
||||||
|
offset(layerm.unsupported_bridge_edges(), scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
|
contact_polygons = diff(contact_polygons, bridges, ApplySafetyOffset::Yes);
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG
|
||||||
|
static int iRun = 0;
|
||||||
|
SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun++),
|
||||||
|
{{{union_ex(offset(layerm.unsupported_bridge_edges(), scale_(SUPPORT_MATERIAL_MARGIN),
|
||||||
|
SUPPORT_SURFACES_OFFSET_PARAMETERS))},
|
||||||
|
{"unsupported_bridge_edges", "orange", 0.5f}},
|
||||||
|
{{union_ex(contact_polygons)}, {"contact_polygons", "blue", 0.5f}},
|
||||||
|
{{union_ex(bridges)}, {"bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f}}});
|
||||||
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
// Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers.
|
// Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers.
|
||||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||||
const PrintObjectConfig &config,
|
const PrintObjectConfig &config,
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ void remove_bridges_from_contacts(
|
|||||||
const LayerRegion &layerm,
|
const LayerRegion &layerm,
|
||||||
float fw,
|
float fw,
|
||||||
Polygons &contact_polygons);
|
Polygons &contact_polygons);
|
||||||
|
//w28
|
||||||
|
void remove_bridges_from_contacts_select_area(
|
||||||
|
const PrintConfig &print_config,
|
||||||
|
const Layer &lower_layer,
|
||||||
|
const LayerRegion &layerm,
|
||||||
|
float fw,
|
||||||
|
Polygons &contact_polygons,
|
||||||
|
const double max_bridge_length = 0);
|
||||||
|
|
||||||
// Turn some of the base layers into base interface layers.
|
// Turn some of the base layers into base interface layers.
|
||||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
||||||
|
|||||||
@@ -1143,6 +1143,9 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
|
|||||||
M_PI * double(object_config.support_material_threshold.value + 1) / 180. : // +1 makes the threshold inclusive
|
M_PI * double(object_config.support_material_threshold.value + 1) / 180. : // +1 makes the threshold inclusive
|
||||||
0.;
|
0.;
|
||||||
float no_interface_offset = 0.f;
|
float no_interface_offset = 0.f;
|
||||||
|
//w28
|
||||||
|
double max_bridge_length = scale_(object_config.max_bridge_length.value);
|
||||||
|
bool bridge_break = object_config.max_bridge_length.value > 0;
|
||||||
|
|
||||||
if (layer_id == 0)
|
if (layer_id == 0)
|
||||||
{
|
{
|
||||||
@@ -1275,7 +1278,9 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
|
|||||||
if (object_config.dont_support_bridges)
|
if (object_config.dont_support_bridges)
|
||||||
//FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge.
|
//FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge.
|
||||||
remove_bridges_from_contacts(print_config, lower_layer, *layerm, fw, diff_polygons);
|
remove_bridges_from_contacts(print_config, lower_layer, *layerm, fw, diff_polygons);
|
||||||
|
//w28
|
||||||
|
if (!object_config.dont_support_bridges && bridge_break)
|
||||||
|
remove_bridges_from_contacts_select_area(print_config, lower_layer, *layerm, fw, diff_polygons, max_bridge_length);
|
||||||
if (diff_polygons.empty())
|
if (diff_polygons.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -203,11 +203,15 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||||||
double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.);
|
double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.);
|
||||||
//FIXME this is a fudge constant!
|
//FIXME this is a fudge constant!
|
||||||
auto enforcer_overhang_offset = scaled<double>(config.support_tree_tip_diameter.value);
|
auto enforcer_overhang_offset = scaled<double>(config.support_tree_tip_diameter.value);
|
||||||
|
//w28
|
||||||
|
double max_bridge_length = scale_(config.max_bridge_length.value);
|
||||||
|
bool bridge_break = config.max_bridge_length.value > 0;
|
||||||
|
|
||||||
|
//w28
|
||||||
size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size()));
|
size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size()));
|
||||||
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
|
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
|
||||||
[&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
|
[&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
|
||||||
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, &throw_on_cancel, &out]
|
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, &throw_on_cancel, &out,bridge_break,max_bridge_length]
|
||||||
(const tbb::blocked_range<LayerIndex> &range) {
|
(const tbb::blocked_range<LayerIndex> &range) {
|
||||||
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||||
const Layer ¤t_layer = *print_object.get_layer(layer_id);
|
const Layer ¤t_layer = *print_object.get_layer(layer_id);
|
||||||
@@ -244,6 +248,12 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||||||
for (const LayerRegion *layerm : current_layer.regions())
|
for (const LayerRegion *layerm : current_layer.regions())
|
||||||
remove_bridges_from_contacts(print_config, lower_layer, *layerm,
|
remove_bridges_from_contacts(print_config, lower_layer, *layerm,
|
||||||
float(layerm->flow(frExternalPerimeter).scaled_width()), overhangs);
|
float(layerm->flow(frExternalPerimeter).scaled_width()), overhangs);
|
||||||
|
}
|
||||||
|
//w28
|
||||||
|
else if (!config.dont_support_bridges && bridge_break) {
|
||||||
|
for (const LayerRegion *layerm : current_layer.regions())
|
||||||
|
remove_bridges_from_contacts_select_area(print_config, lower_layer, *layerm, float(scale_(config.extrusion_width)),
|
||||||
|
overhangs, max_bridge_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//check_self_intersections(overhangs, "generate_overhangs1");
|
//check_self_intersections(overhangs, "generate_overhangs1");
|
||||||
|
|||||||
@@ -316,6 +316,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||||||
toggle_field("support_material_threshold", have_support_material_auto);
|
toggle_field("support_material_threshold", have_support_material_auto);
|
||||||
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
|
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
|
||||||
toggle_field("support_material_closing_radius", have_support_material && support_material_style == smsSnug);
|
toggle_field("support_material_closing_radius", have_support_material && support_material_style == smsSnug);
|
||||||
|
//w28
|
||||||
|
bool can_remove_bridge = have_support_material && !config->opt_bool("dont_support_bridges");
|
||||||
|
toggle_field("max_bridge_length", can_remove_bridge);
|
||||||
|
|
||||||
const bool has_organic_supports = support_material_style == smsOrganic &&
|
const bool has_organic_supports = support_material_style == smsOrganic &&
|
||||||
(config->opt_bool("support_material") ||
|
(config->opt_bool("support_material") ||
|
||||||
|
|||||||
@@ -1562,6 +1562,8 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("support_material_xy_spacing", category_path + "xy-separation-between-an-object-and-its-support");
|
optgroup->append_single_option_line("support_material_xy_spacing", category_path + "xy-separation-between-an-object-and-its-support");
|
||||||
optgroup->append_single_option_line("dont_support_bridges", category_path + "dont-support-bridges");
|
optgroup->append_single_option_line("dont_support_bridges", category_path + "dont-support-bridges");
|
||||||
optgroup->append_single_option_line("support_material_synchronize_layers", category_path + "synchronize-with-object-layers");
|
optgroup->append_single_option_line("support_material_synchronize_layers", category_path + "synchronize-with-object-layers");
|
||||||
|
//w28
|
||||||
|
optgroup->append_single_option_line("max_bridge_length", category_path + "max_bridge_length");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Organic supports"));
|
optgroup = page->new_optgroup(L("Organic supports"));
|
||||||
const std::string path = "organic-supports_480131#organic-supports-settings";
|
const std::string path = "organic-supports_480131#organic-supports-settings";
|
||||||
|
|||||||
Reference in New Issue
Block a user