-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented feature request #1405 minimum shell thickness option #3885
Conversation
-Added the option to libslic3r -Created some of the necessary checks for illegal values
-This could be switched to match the extrusion width, but we already know there will only be 1 perimeter so this is probably more logical
-Added a method in PerimeterGenerator to determine the amount of perimeters needed to meet min_shell_thickness
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, good work. I liked the approach, just had some notes about style and test robustness that should be addressed.
int generated_perimeters = perimeters + extra_perimeters - 1; | ||
long int min_shell_thickness, shell_thickness = 0; | ||
|
||
min_shell_thickness = this->config->min_shell_thickness * 1000000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style
Prefer use of the scale_ and unscale functions (see libslic3r.h) instead of the magic number multiplication here.
You can also define and assign (with unscale) min_shell_thickness as an auto
.
int | ||
PerimeterGenerator::num_loops(int perimeters, int extra_perimeters) { | ||
int generated_perimeters = perimeters + extra_perimeters - 1; | ||
long int min_shell_thickness, shell_thickness = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style
We don't use long int
, just long
(when we aren't using something that typedefs to long
, like coord_t
).
Suggest auto shell_thickness = this->ext_perimeter_flow.scaled_width()
(yay c++11).
xs/src/libslic3r/PrintConfig.cpp
Outdated
def->category = "Layers and Perimeters"; | ||
def->sidetext = "mm"; | ||
def->tooltip = "Minimum shell thickness in mm"; | ||
def->cli = "min-shell-thickness=f"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation
Update slic3r.pl and README.md to add your option to them.
@@ -54,7 +71,7 @@ PerimeterGenerator::process() | |||
for (Surfaces::const_iterator surface = this->slices->surfaces.begin(); | |||
surface != this->slices->surfaces.end(); ++surface) { | |||
// detect how many perimeters must be generated for this island | |||
const int loop_number = this->config->perimeters + surface->extra_perimeters -1; // 0-indexed loops | |||
const int loop_number = num_loops(this->config->perimeters, surface->extra_perimeters);//this->config->perimeters + surface->extra_perimeters-1; // 0-indexed loops |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the way you extended this to increase the number of loops if necessary.
t/perimeters.t
Outdated
$in_loop = 0; | ||
} | ||
}); | ||
ok !(grep { $_ % $config->min_shell_thickness/$config->perimeter_extrusion_width } values %perimeters), 'should be 6 perimeters'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Robustness
Please add another couple test cases to check that it rounds up as expected if the perimeter width isn't a multiple of the min-width. Just in case @alexrj or I blunder in and break that condition somehow ;)
Take a look at the first test in t/support.t, it puts the actual test into a subroutine and then calls that routine with different options. Here you'd just need to round up the division in the test itself to verify the number of perimeters that were generated.
lib/Slic3r/GUI/PresetEditor.pm
Outdated
@@ -759,10 +760,11 @@ sub _update { | |||
|
|||
my $config = $self->{config}; | |||
|
|||
if ($config->spiral_vase && !($config->perimeters == 1 && $config->top_solid_layers == 0 && $config->fill_density == 0 && $config->support_material == 0)) { | |||
if ($config->spiral_vase && !($config->perimeters == 1 && $config->min_shell_thickness == 0 && $config->top_solid_layers == 0 && $config->fill_density == 0 && $config->support_material == 0)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I probably would have missed this myself.
I just realized I forgot about the top and bottom of the model. This should also increase the amount of solid top/bottom layers yeah? |
I'm not so sure myself. |
-Removed the magic number in PerimeterGenerator::num_loops() -Added more test cases in perimeters.t -Added documentation of the new feature in slic3r.pl and README.md
PerimeterGenerator::num_loops(int perimeters, int extra_perimeters) | ||
{ | ||
int generated_perimeters = perimeters + extra_perimeters - 1; | ||
long min_shell_thickness = scale_(this->config->min_shell_thickness); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use coord_t
instead of long
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or auto
(which is my preference as you are instantiating the value already). If @alexrj disagrees, go with what he said. ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexrj what is the context for coord_t
? What is the assumption/guarantee with using it?
@@ -54,7 +71,7 @@ PerimeterGenerator::process() | |||
for (Surfaces::const_iterator surface = this->slices->surfaces.begin(); | |||
surface != this->slices->surfaces.end(); ++surface) { | |||
// detect how many perimeters must be generated for this island | |||
const int loop_number = this->config->perimeters + surface->extra_perimeters -1; // 0-indexed loops | |||
const int loop_number = num_loops(this->config->perimeters, surface->extra_perimeters);//this->config->perimeters + surface->extra_perimeters-1; // 0-indexed loops |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note about semantics: loop_number
holds the number of loops diminuished by 1. This is related to the implementation of the subsequent code, and I admit the variable could be named in a better way. But when you expose a num_loops()
method, it should output the actual number of loops. Then you can subtract 1 in the caller method if it's needed by its implementation.
By the way, I don't see the need for a separate method just for this calculation. I'd embed the logic in the main method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By embedding it in the main method you can also cache min_shell_thickness
and this->ext_perimeter_flow.scaled_width()
without recalculating them every time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loop_number is a constant. Any preference on how to set it? I thought a new method would be okay but you do bring up a good point.
if (shell_thickness < min_shell_thickness) { | ||
shell_thickness = min_shell_thickness - this->ext_perimeter_flow.scaled_width(); | ||
generated_perimeters = ceil((float)shell_thickness/this->ext_perimeter_flow.scaled_width()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why calling this->ext_perimeter_flow.scaled_width()
and /this->ext_perimeter_flow.scaled_width()
twice?
By the way, I would simplify the logic:
- Calculate how many loops are needed for the requested min_shell_thickness (considering one ext_perimeter followed by many normal perimeters, of course).
- Increase loop number until min_shell_thickness is covered.
Also, write some comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And you should just skip all of this math if min_shell_thickness is 0.
xs/src/libslic3r/PrintConfig.cpp
Outdated
def->label = "Minimum shell thickness"; | ||
def->category = "Layers and Perimeters"; | ||
def->sidetext = "mm"; | ||
def->tooltip = "Minimum shell thickness in mm"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be more clear. Minimum shell thickness is an alternative way for configuring perimeters and solid shells. If it's set to a non-zero value, they will be automatically increased until the configured value is reached.
Thank you for this. I added some comments to the code. Here's more:
|
Thank you for the comments. I will get to these soon. |
I made changes that should work. I'm running a build on my end real quick to make sure and I will then push the changes. I'll then get to working on the 3 other things you mentioned. |
We could break constness. Inlining the new code would make semantic sense
for a non-const number.
So would using another variable and assigning to the const loop_num
|
I came up with a solution that I think you will like that I based on some of the semantics Alex talked about. Should be pushed in the next couple minutes. |
-Removed the num_loops function from PerimeterGenerator -Added a scalled min_shell_thickness variable to PerimeterGenerator -Changed the loop_number logic to use a previously defined variable loops
I forgot to change the tooltip. I will change it and push it with the next set of changes. |
I've been trying to find where slic3r creates the layer objects and determines whether or not they are solid and it seems like its in Object.pm. Does this sound right? |
-Added min shell to invalidate state method -Created additional checks in PresetEditor and LayerRegion for min shell -Fixed the tooltip to be more descriptive
The top and bottom solid layers implementation is in perl. I don't know much perl so I'm going to create another branch+pull request for a version of the method written in C++ before I finish this up. |
The code as-is looks good; merging so that it may be extended. |
I hope this is no real issue! I get this, when Slic3r is started with |
@foreachthing I think it's because a missing '&' in line 806 $config->min_shell_thickness == 0 & $config->top_solid_layers == 0
# Instead of
$config->min_shell_thickness == 0 && $config->top_solid_layers == 0 |
This adds a new print config option, minimum shell thickness. It works as described in the issue page by alexrj. The current configuration, when paired with the generate extra perimeters option, will only add perimeters when both the normal and extra perimeters combined don't meet the shell thickness requirements.
Fixes #1405