Skip to content
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

Merged
merged 9 commits into from
May 22, 2018

Conversation

curieos
Copy link
Contributor

@curieos curieos commented Apr 16, 2017

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

curieos added 4 commits April 14, 2017 01:58
-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
@lordofhyphens lordofhyphens added Feature request This is an idea for a new feature in Slic3r Perimeters labels Apr 16, 2017
@lordofhyphens lordofhyphens added this to the 1.3.0 milestone Apr 16, 2017
Copy link
Member

@lordofhyphens lordofhyphens left a 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;
Copy link
Member

@lordofhyphens lordofhyphens Apr 16, 2017

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;
Copy link
Member

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).

def->category = "Layers and Perimeters";
def->sidetext = "mm";
def->tooltip = "Minimum shell thickness in mm";
def->cli = "min-shell-thickness=f";
Copy link
Member

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
Copy link
Member

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';
Copy link
Member

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.

@@ -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)) {
Copy link
Member

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.

@curieos
Copy link
Contributor Author

curieos commented Apr 16, 2017

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?

@lordofhyphens
Copy link
Member

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);
Copy link
Member

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

Copy link
Member

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. ;)

Copy link
Member

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
Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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());
}
Copy link
Member

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:

  1. Calculate how many loops are needed for the requested min_shell_thickness (considering one ext_perimeter followed by many normal perimeters, of course).
  2. Increase loop number until min_shell_thickness is covered.

Also, write some comments.

Copy link
Member

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.

def->label = "Minimum shell thickness";
def->category = "Layers and Perimeters";
def->sidetext = "mm";
def->tooltip = "Minimum shell thickness in mm";
Copy link
Member

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.

@alranel
Copy link
Member

alranel commented Apr 20, 2017

Thank you for this. I added some comments to the code. Here's more:

  • Solid layers (top/solid) shall be increased as well. Shell = vertical shell + horizontal shell.
  • Option shall be added to the GUI (PresetEditor) as well.
  • Option shall be added to the relevant place in PrintRegion::invalidate_state_by_config() as well.

@curieos
Copy link
Contributor Author

curieos commented Apr 21, 2017

Thank you for the comments. I will get to these soon.

@curieos
Copy link
Contributor Author

curieos commented Apr 21, 2017

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.

@lordofhyphens
Copy link
Member

lordofhyphens commented Apr 21, 2017 via email

@curieos
Copy link
Contributor Author

curieos commented Apr 21, 2017

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
@curieos
Copy link
Contributor Author

curieos commented Apr 21, 2017

I forgot to change the tooltip. I will change it and push it with the next set of changes.

@curieos
Copy link
Contributor Author

curieos commented Apr 21, 2017

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
@curieos
Copy link
Contributor Author

curieos commented Apr 24, 2017

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.

@alranel alranel modified the milestones: 1.3.1, 1.3.0 May 1, 2017
@lordofhyphens lordofhyphens merged commit f3b5909 into slic3r:master May 22, 2018
@lordofhyphens
Copy link
Member

The code as-is looks good; merging so that it may be extended.

@foreachthing
Copy link
Member

I hope this is no real issue! I get this, when Slic3r is started with Slic3r-debug-console.exe:
Possible precedence problem on bitwise & operator at C:/Slic3r-master.2018.05.23.1703.f3b5909/lib/Slic3r/GUI/PresetEditor.pm line 806.

@Samir55
Copy link
Member

Samir55 commented May 23, 2018

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature request This is an idea for a new feature in Slic3r Perimeters
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants