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

Improvements in Inner Outer Inner wall ordering logic #6138

Merged
merged 24 commits into from
Aug 13, 2024

Conversation

igiannakas
Copy link
Contributor

@igiannakas igiannakas commented Jul 14, 2024

Introducing distance checking when reordering perimeters for inner outer inner to catch more edge cases.
Testing is in progress hence marking as draft

Explanation of changes / issues addressed:

  1. This PR fixes an issue with Arachne wall ordering where on some layers the external wall of the model would not be printed first, but rather a "hole" external wall. While this doesnt matter much outer inner ordering, it does matter for Inner Outer Inner as it can change the wall ordering between consecutive layers as the outer inner mode is used as its basis

The examples below use Outer Inner to better showcase the identified issue:

Before - Layer 41-46
image
Before - Layer 48-49
image

Now the algorithm re-orders the external walls always setting the external wall of the model as first in the list for IOI wall ordering. I have not made this change in the Outer Inner ordering mode, as the clustering algorithm works well there and it doesn't matter quality wise that the hole is printed before the contour, as both start with the external perimeter first.

  1. On some occasions where a second internal perimeter is proximate to both a contour (outer model wall) and a hole (external wall internal to the model), due to the way perimeter grouping is done in Arachne, the last external wall, be that a contour or a hole, always "grabs" the internal perimeters and associates them with it. Again, while this works well for outer inner wall ordering, it means that the "contour" external walls are "disadvantaged" quality wise compared to "holes" as IOI ordering would always happen for holes but would fall back to outer inner for contours when internal perimeters where shared between them. As contours are the most visible part of the model, this led to issues with external appearance as it was causing the wall sequencing to "flip flop" between Outer-Inner and Inner-Outer-Inner depending on the distance that the hole walls had to the contour walls.

For example:
In the below we can see the external wall printed with no neighbouring perimeters at all
image
That is because the internal walls next to the outer benchy shell are associated to the hole (i.e. the "pole" on the benchy)
image
image
Note how the IOI algorithm before tried to fix this by at least finding one internal perimeter to print - it just did not know proximity so the selected line was not always optimal.

In this PR I have implemented a new perimeter re-ordering algorithm that reallocates the first internal, second internal and so forth, perimeters back to the external perimeter.

After - the external contour now gets ownership of the internal perimeters, on the assumption that external model wall quality is more important than "hole" surface finish.
image
image

This also helps with more complicated shapes, like the below
Before: The outer wall is printed after a long travel which isn't necessary as it has plenty of perimeters next to it to use. However these were allocated to a "hole" so it cannot re-order using the IOI sequence and instead falls back to OI.
image

After: - the external contour (wall) takes ownership of the perimeters.
image

How this PR works:

The ordering algorithm before executing the IOI re-ordering sequence, traverses the ordered extrusions list and checks that neighbouring perimeters to the external contour perimeter are ordered in the right way. If they are not, it re-orders the internal perimeters, up to the second internal perimeter and attaches them to the external contour.

How are we checking for proximity?
Minimum distance
I've experimented with the Hausdorf distance algorithm and the minimum path segment distance algorithm to define proximity. As we are looking for perimeters that are touching the external contour, the minimum distance algorithm of any two points between the base perimeter and the candidate perimeter for reordering yielded better results.

Algorithm explanation:

  1. The algorithm initialises with the dominant contour of the island - i.e. the outer visible surface of the model.
  2. Then it checks the list of extrusions on whether any of them are proximate - using the minimum distance and a search radius dependant on whether we are searching from an external perimeter or from an internal one.
  3. If it found any, it brings it up on the list, immediately after the outer wall.
  4. It then takes the perimeter found and searches for proximates to that one. If it finds any, it brings it up on the list and so forth until no more perimeters are left.
  5. The algorithm always finds perimeters in ascending inset index order, so it won't grab a perimeter 1 from a neighbouring feature on the same island when searching for perimeter index 2. However it WILL grab perimeter 2's (second internal or more) from a proximate island leaving it with 2 perimeters to print only. However as we are optimising for external surface finish, and de-prioritising the finish of the contours this is not an issue.
  6. Then the algorithm also finds the longest perimeter 2+ and sets it to be printed last in the IOI re-ordering. That ordering of the last perimeter to be printed before the external one based on length allows the maximum opportunity for the nozzle pressure to equalise before printing the external perimeter.

This revision to the perimeter ordering has also enabled the reduction in complexity of the old heuristics performed to attempt to find the right perimeter sequence based on inset indexes, as now the perimeters are ordered in the right way, and in an optimal manner for IOI ordering from the beginning.

Finally, unfortunately as the seam data is not present in this code class (they are generated later in the slicing pipeline) we cannot use the start and end points of the extrusion as mechanisms to re-order the perimeters so travel between the start and end points is minimised. So we are left with trying to find a proxy that helps with sequencing - in this case it is proximity and perimeter length.

This change affects Arachne perimeter generation only, as it is the one susceptible to suboptimal perimeter ordering for IOI mode compared to classic. This is because of the variable line widths that Arachne is using, resulting in perimeters being shared between islands instead of gap fill operations to fill the space between the islands.

Credits:

Credit to discord user KillSwitch who's worked with me to replicate the ordering issue he was facing plus ideas on how this could be addressed and for being the test subject :) STL above was provided by KillSwitch when replicating the issue.

@igiannakas igiannakas marked this pull request as ready for review July 15, 2024 11:08
@igiannakas igiannakas marked this pull request as draft July 17, 2024 19:57
@igiannakas igiannakas marked this pull request as ready for review July 18, 2024 13:55
@igiannakas
Copy link
Contributor Author

Updating status to ready to review. Further enhancements may come from future testing, however it is in a place now to review and get feedback.

…scenarios where multiple external perimeters are contained in the same island.
@dewi-ny-je
Copy link
Contributor

I hope that once this one and #5996 are merged a new beta of Orca will be released for everyone to test it.

Copy link
Owner

@SoftFever SoftFever left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @igiannakas
I had a rough overview of the changes, and have some comments of the code structure, could you take a look?

I need more time to deep dive into the algos.
Meanwhile, do you by any chance measured/noticed the performance impact?

src/libslic3r/PerimeterGenerator.cpp Outdated Show resolved Hide resolved
src/libslic3r/PerimeterGenerator.cpp Outdated Show resolved Hide resolved
src/libslic3r/PerimeterGenerator.cpp Outdated Show resolved Hide resolved
src/libslic3r/PerimeterGenerator.cpp Outdated Show resolved Hide resolved
@igiannakas
Copy link
Contributor Author

Awesome thank you for the feedback, much appreciated!!! I’ll get on to them next week when back home.

Performace wise I have not noticed anything huge; however I’m using a MacBook Pro M1 Pro which never struggled really with slicing anyway. Have been using it since I opened the PR with reasonable complex models (incl multi color).

That being said, I’m not expecting a huge hit as the tree is “pruning” itself - start with external contour, search perimeters in the same island for nearest inset index 1, store them, then search for inset index 2, store etc. if the perimeter is already stored, it doesn’t search for it again so the perimeter list reduces as we scan through the list - the first scan is the most expensive and it’s bound by the number of inset index 1 perimeters available. If that makes sense :)

I’m expecting more of a hit on models with multiple perimeter inset index 1 in the same island. For the rest (as in simple islands with 1 inset index perimeter) it shouldn’t make any difference as the perimeter list is small.

Also as the perimeter generation is running multi threaded it’s somewhat ok but a test with a slower computer may be useful.

@igiannakas
Copy link
Contributor Author

igiannakas commented Aug 9, 2024

Hope the below commentary helps with the review Softfever!

findAllTouchingPerimeters Function:

This function is identifies perimeters that are in close proximity to a set of reference perimeters. Given a collection of perimeters, each with an associated position and inset index (which indicates whether the perimeter is external or internal), the function searches for other perimeters that are "touching" i.e. are near the reference perimeters within a specified distance threshold.

This function creates a list of perimeters that are within a certain distance from a reference set, distinguishing between external and internal perimeters based on their inset index. The function finds perimeters of a specific inset index (e.g., first internal perimeters) that are close to the reference.
Thresholds: It uses different distance thresholds depending on whether the reference perimeter is external (inset index 0) or internal (inset index 1 or higher).
Output: The function returns a list of indices corresponding to perimeters that are found to be touching to the specified reference perimeter and are of the requested inset index.

reorderPerimetersByProximity Function:
This function aims to optimize the order in which perimeters are printed, based on their spatial proximity. Starting with external contour perimeters, the function reorganises the perimeters so that those closest to each other are printed sequentially. It performs the reordering by starting from the outermost (external) contour perimeters and moves inward to internal ones.

Optimization Strategy: The function begins with the outermost perimeters and finds the closest internal perimeters that should follow in the sequence. It prioritizes larger, dominant perimeters that are more impactful on the overall process (as we want the largest amount of extrusion to have happened before we print the external perimeter to ensure the nozzle is primed properly).

bringContoursToFront function:
This is a helper function to make sure the external contour wall perimeter is brought forward to the list as this is used to "anchor" the search.

Once we have a sequenced outer-inner list of perimeters based on proximity, we then run the IOI re-ordering as before, moving the inset index 2+ perimeter ahead of the inset index 0 + 1. This part has remained unchanged, and is slightly simplified due to the more consistent ordering outputs from the above revised algorithm.

Copy link
Owner

@SoftFever SoftFever left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good
Thank you!

@SoftFever SoftFever merged commit 9a26001 into SoftFever:main Aug 13, 2024
15 checks passed
@igiannakas
Copy link
Contributor Author

Awesome thank you :)

I’ll possibly carry on refining this over the next few months as it’s my primary print mode too :)

henrivdr pushed a commit to henrivdr/OrcaSlicer that referenced this pull request Aug 27, 2024
* Improvements in Inner Outer Inner wall ordering logic

* Updated to BFS algorithm, made ordering more robust and corrected edge cases

* Doc updates

* Refinements in perimeter sorting

* Removal of touch threshold and code debugging to improve sequencing

* Code cleanup

* Code refinements on perimeter distance thresholds

* Extend perimeter re-ordering to more than inset index 2, to reduce travel moves when printing neighbouring features

* Refinements to IOI perimeter re-ordering algorithm to improve travel scenarios where multiple external perimeters are contained in the same island.

* Documentation updates

* Removed unnecessary code

* Removed bespoke to_points function and replaced with ExtrusionLine member already present. Removed squaredDistance and replaced with Eigen library call.

* Refactor code to move distancing functions to the multipoint class. Renamed for more clarity on their purpose.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants