mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-04 05:50:48 +08:00
commit
3b338e5f84
@ -454,7 +454,7 @@ sub options {
|
||||
perimeter_acceleration infill_acceleration bridge_acceleration
|
||||
first_layer_acceleration default_acceleration
|
||||
skirts skirt_distance skirt_height min_skirt_length
|
||||
brim_connections_width brim_width interior_brim_width
|
||||
brim_connections_width brim_ears brim_ears_max_angle brim_width interior_brim_width
|
||||
support_material support_material_threshold support_material_max_layers support_material_enforce_layers
|
||||
raft_layers
|
||||
support_material_pattern support_material_spacing support_material_angle
|
||||
@ -593,6 +593,8 @@ sub build {
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Brim');
|
||||
$optgroup->append_single_option_line('brim_width');
|
||||
$optgroup->append_single_option_line('brim_ears');
|
||||
$optgroup->append_single_option_line('brim_ears_max_angle');
|
||||
$optgroup->append_single_option_line('interior_brim_width');
|
||||
$optgroup->append_single_option_line('brim_connections_width');
|
||||
}
|
||||
@ -949,6 +951,9 @@ sub _update {
|
||||
# perimeter_extruder uses the same logic as in Print::extruders()
|
||||
$self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim);
|
||||
|
||||
$self->get_field('brim_ears')->toggle($have_brim);
|
||||
$self->get_field('brim_ears_max_angle')->toggle($have_brim && $config->brim_ears);
|
||||
|
||||
my $have_support_material = $config->support_material || $config->raft_layers > 0;
|
||||
my $have_support_interface = $config->support_material_interface_layers > 0;
|
||||
my $have_support_pillars = $have_support_material && $config->support_material_pattern eq 'pillars';
|
||||
|
@ -554,6 +554,8 @@ $j
|
||||
of filament on the first layer, for each extruder (mm, 0+, default: $config->{min_skirt_length})
|
||||
--brim-width Width of the brim that will get added to each object to help adhesion
|
||||
(mm, default: $config->{brim_width})
|
||||
--brim-ears Print brim only on sharp corners.
|
||||
--brim-ears-max-angle Maximum angle considered for adding brim ears. (degrees, default: $config->{brim_ears_max_angle})
|
||||
--interior-brim-width Width of the brim that will get printed inside object holes to help adhesion
|
||||
(mm, default: $config->{interior_brim_width})
|
||||
|
||||
|
@ -158,7 +158,7 @@ public:
|
||||
"perimeter_acceleration"s, "infill_acceleration"s, "bridge_acceleration"s,
|
||||
"first_layer_acceleration"s, "default_acceleration"s,
|
||||
"skirts"s, "skirt_distance"s, "skirt_height"s, "min_skirt_length"s,
|
||||
"brim_connections_width"s, "brim_width"s, "interior_brim_width"s,
|
||||
"brim_connections_width"s, "brim_ears"s, "brim_ears_max_angle"s, "brim_width"s, "interior_brim_width"s,
|
||||
"support_material"s, "support_material_threshold"s, "support_material_max_layers"s, "support_material_enforce_layers"s,
|
||||
"raft_layers"s,
|
||||
"support_material_pattern"s, "support_material_spacing"s, "support_material_angle"s, ""s,
|
||||
|
@ -153,6 +153,51 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") {
|
||||
REQUIRE(tool == config->getInt("support_material_extruder") - 1);
|
||||
}
|
||||
}
|
||||
WHEN("brim width to 1 with layer_width of 0.5") {
|
||||
config->set("skirts", 0);
|
||||
config->set("first_layer_extrusion_width", 0.5);
|
||||
config->set("brim_width", 1);
|
||||
config->set("brim_ears", false);
|
||||
|
||||
THEN("2 brim lines") {
|
||||
Slic3r::Model model;
|
||||
auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
|
||||
print->process();
|
||||
REQUIRE(print->brim.size() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("brim ears on a square") {
|
||||
config->set("skirts", 0);
|
||||
config->set("first_layer_extrusion_width", 0.5);
|
||||
config->set("brim_width", 1);
|
||||
config->set("brim_ears", true);
|
||||
config->set("brim_ears_max_angle", 91);
|
||||
|
||||
Slic3r::Model model;
|
||||
auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
|
||||
print->process();
|
||||
|
||||
THEN("Four brim ears") {
|
||||
REQUIRE(print->brim.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WHEN("brim ears on a square but with a too small max angle") {
|
||||
config->set("skirts", 0);
|
||||
config->set("first_layer_extrusion_width", 0.5);
|
||||
config->set("brim_width", 1);
|
||||
config->set("brim_ears", true);
|
||||
config->set("brim_ears_max_angle", 89);
|
||||
|
||||
THEN("no brim") {
|
||||
Slic3r::Model model;
|
||||
auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
|
||||
print->process();
|
||||
REQUIRE(print->brim.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Object is plated with overhang support and a brim") {
|
||||
config->set("layer_height", 0.4);
|
||||
|
@ -349,6 +349,8 @@ Print::invalidate_state_by_config(const PrintConfigBase &config)
|
||||
osteps.insert(posSupportMaterial);
|
||||
} else if (opt_key == "brim_width"
|
||||
|| opt_key == "interior_brim_width"
|
||||
|| opt_key == "brim_ears"
|
||||
|| opt_key == "brim_ears_max_angle"
|
||||
|| opt_key == "brim_connections_width") {
|
||||
steps.insert(psBrim);
|
||||
steps.insert(psSkirt);
|
||||
@ -1084,6 +1086,7 @@ Print::_make_brim()
|
||||
|
||||
const coord_t grow_distance = flow.scaled_width()/2;
|
||||
Polygons islands;
|
||||
Points pt_ears;
|
||||
|
||||
for (PrintObject* object : this->objects) {
|
||||
const Layer* layer0 = object->get_layer(0);
|
||||
@ -1103,6 +1106,10 @@ Print::_make_brim()
|
||||
for (Polygon p : object_islands) {
|
||||
p.translate(copy);
|
||||
islands.push_back(p);
|
||||
if(this->config.brim_ears)
|
||||
for (const Point &p_corner : p.convex_points(this->config.brim_ears_max_angle.value * PI / 180.0)) {
|
||||
pt_ears.push_back(p_corner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1123,6 +1130,124 @@ Print::_make_brim()
|
||||
));
|
||||
}
|
||||
|
||||
if(this->config.brim_ears){
|
||||
|
||||
//create ear pattern
|
||||
coord_t size_ear = (scale_(this->config.brim_width.value) - flow.scaled_spacing());
|
||||
Polygon point_round;
|
||||
point_round.points.push_back(Point(size_ear*1, 0*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.966, 0.26*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.87, 0.5*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.7, 0.7*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.5, 0.87*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.26, 0.966*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0, 1*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.26, 0.966*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.5, 0.87*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.7, 0.7*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.87, 0.5*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.966, 0.26*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-1, 0*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.966, -0.26*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.87, -0.5*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.7, -0.7*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.5, -0.87*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*-0.26, -0.966*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0, -1*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.26, -0.966*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.5, -0.87*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.7, -0.7*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.87, -0.5*size_ear));
|
||||
point_round.points.push_back(Point(size_ear*0.966, -0.26*size_ear));
|
||||
|
||||
//create ears
|
||||
Polygons mouse_ears;
|
||||
for (Point pt : pt_ears) {
|
||||
mouse_ears.push_back(point_round);
|
||||
mouse_ears.back().translate(pt);
|
||||
}
|
||||
|
||||
//intersection
|
||||
Polylines lines = intersection_pl(union_pt_chained(loops), mouse_ears);
|
||||
|
||||
//reorder them
|
||||
Polylines lines_sorted;
|
||||
Polyline* previous = NULL;
|
||||
Polyline* best = NULL;
|
||||
double best_dist = -1;
|
||||
size_t best_idx = 0;
|
||||
while (lines.size() > 0) {
|
||||
if (previous == NULL) {
|
||||
lines_sorted.push_back(lines.back());
|
||||
previous = &lines_sorted.back();
|
||||
lines.erase(lines.end() - 1);
|
||||
} else {
|
||||
best = NULL;
|
||||
best_dist = -1;
|
||||
best_idx = 0;
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
Polyline &viewed_line = lines[i];
|
||||
double dist = viewed_line.points.front().distance_to(previous->points.front());
|
||||
dist = std::min(dist, viewed_line.points.front().distance_to(previous->points.back()));
|
||||
dist = std::min(dist, viewed_line.points.back().distance_to(previous->points.front()));
|
||||
dist = std::min(dist, viewed_line.points.back().distance_to(previous->points.back()));
|
||||
if (dist < best_dist || best == NULL) {
|
||||
best = &viewed_line;
|
||||
best_dist = dist;
|
||||
best_idx = i;
|
||||
}
|
||||
}
|
||||
if (best != NULL) {
|
||||
//copy new line inside the sorted array.
|
||||
lines_sorted.push_back(lines[best_idx]);
|
||||
lines.erase(lines.begin() + best_idx);
|
||||
|
||||
//connect if near enough
|
||||
if (lines_sorted.size() > 1) {
|
||||
size_t idx = lines_sorted.size() - 2;
|
||||
bool connect = false;
|
||||
if (lines_sorted[idx].points.back().distance_to(lines_sorted[idx + 1].points.front()) < flow.scaled_spacing() * 2) {
|
||||
connect = true;
|
||||
} else if (lines_sorted[idx].points.back().distance_to(lines_sorted[idx + 1].points.back()) < flow.scaled_spacing() * 2) {
|
||||
lines_sorted[idx + 1].reverse();
|
||||
connect = true;
|
||||
} else if (lines_sorted[idx].points.front().distance_to(lines_sorted[idx + 1].points.front()) < flow.scaled_spacing() * 2) {
|
||||
lines_sorted[idx].reverse();
|
||||
connect = true;
|
||||
} else if (lines_sorted[idx].points.front().distance_to(lines_sorted[idx + 1].points.back()) < flow.scaled_spacing() * 2) {
|
||||
lines_sorted[idx].reverse();
|
||||
lines_sorted[idx + 1].reverse();
|
||||
connect = true;
|
||||
}
|
||||
|
||||
if (connect) {
|
||||
//connect them
|
||||
lines_sorted[idx].points.insert(
|
||||
lines_sorted[idx].points.end(),
|
||||
lines_sorted[idx + 1].points.begin(),
|
||||
lines_sorted[idx + 1].points.end());
|
||||
lines_sorted.erase(lines_sorted.begin() + idx + 1);
|
||||
idx--;
|
||||
}
|
||||
}
|
||||
|
||||
//update last position
|
||||
previous = &lines_sorted.back();
|
||||
} else {
|
||||
previous == NULL;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//push into extrusions
|
||||
for (Polyline &to_extrude : lines_sorted) {
|
||||
ExtrusionPath path(erSkirt, mm3_per_mm, flow.width, flow.height);
|
||||
path.polyline = to_extrude;
|
||||
this->brim.append(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Polygons chained = union_pt_chained(loops);
|
||||
for (Polygons::const_reverse_iterator p = chained.rbegin(); p != chained.rend(); ++p) {
|
||||
|
@ -160,6 +160,23 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("brim_ears", coBool);
|
||||
def->label = __TRANS("Exterior brim ears");
|
||||
def->category = __TRANS("Skirt and brim");
|
||||
def->tooltip = __TRANS("Draw the brim only over the sharp edges of the model.");
|
||||
def->cli = "brim-ears!";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("brim_ears_max_angle", coFloat);
|
||||
def->label = __TRANS("Brim ears Maximum Angle");
|
||||
def->category = __TRANS("Skirt and brim");
|
||||
def->tooltip = __TRANS("Maximum angle for a corner to place a brim ear.");
|
||||
def->sidetext = "°";
|
||||
def->cli = "brim-ears-max-angle=f";
|
||||
def->min = 0;
|
||||
def->max = 180;
|
||||
def->default_value = new ConfigOptionFloat(125);
|
||||
|
||||
def = this->add("brim_width", coFloat);
|
||||
def->label = __TRANS("Exterior brim width");
|
||||
def->category = __TRANS("Skirt and brim");
|
||||
|
@ -433,6 +433,8 @@ class PrintConfig : public GCodeConfig
|
||||
ConfigOptionFloat bridge_acceleration;
|
||||
ConfigOptionInt bridge_fan_speed;
|
||||
ConfigOptionFloat brim_connections_width;
|
||||
ConfigOptionBool brim_ears;
|
||||
ConfigOptionFloat brim_ears_max_angle;
|
||||
ConfigOptionFloat brim_width;
|
||||
ConfigOptionBool complete_objects;
|
||||
ConfigOptionBool cooling;
|
||||
@ -495,6 +497,8 @@ class PrintConfig : public GCodeConfig
|
||||
OPT_PTR(bridge_acceleration);
|
||||
OPT_PTR(bridge_fan_speed);
|
||||
OPT_PTR(brim_connections_width);
|
||||
OPT_PTR(brim_ears);
|
||||
OPT_PTR(brim_ears_max_angle);
|
||||
OPT_PTR(brim_width);
|
||||
OPT_PTR(complete_objects);
|
||||
OPT_PTR(cooling);
|
||||
|
Loading…
x
Reference in New Issue
Block a user