-
-
Notifications
You must be signed in to change notification settings - Fork 890
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
Fix simplify() and test it extensively #1214
Conversation
The previous test only considered single corners, while simplify() works cumulatively. Even though one corner might not simplify based on its current geometry, it might be simplified if the previous corner was simplified. This seems to be related to the fact that the spiral has self-intersectiong geometry. The simplification of more segments can result in a smaller error because the spiral loops back unto itself. In the new test the whole spiral is considered to be a region of small errors and the whole thing is simplifiable, except that we added unsimplifiable geometry in order to prevent the collapse of the whole region, which was another problem of the original test
… simplify() simplify() is not precise and might not optimally simplify We therefore allow for twice the optimal amount of segments in the output
due to intermediate simplification, the total error should be as large as the diameter of the spiral, not the radius.
…a vertex within the loop it was only checking the previous segment, at the end of the loop it was requiring either segment instead of both
This PR now also includes a fix for the changed long line segment problems shown in figure 2 and 3 of this thread. |
captures the intent of the original spiral test called simplifyLimitedError
the Y component might be quite high, so we introduce points in between two consecutive X values with an intermediate Y also we add some arbitrary long segments in there to test robustness against a mix of high poly and low poly
for debugging purposes
If consecutive points are considered the colinearity is a moving target and the removal escalates and generates rough gcode when the input model is extremely high poly.
The function loops over as many points as size(), so we don't need to handle the first point outside of the loop. The code for checking colinearity was buggy and could escalate. Now we simply interpret the function requirements as stating that the smallest_line_segment criterion ca be ignored if the local deviation is smaller than 5 micron. We therefore use the same vertex removing code for those small errors as for larger errors.
whole polygons were removed when simplify could remove all first vertices until it got to the last one. When it checked whether it could remove the last one it checked a point against itself, which meant that the area was always zero and so it would always also remove the last 2 vertices as well.
The testing criteria didn't correspond to what the documentation requires of the function. The test case used to depend too much on implementation detail.
removes duplicate code should always execute the same
test which a degenerate vertex which lies far away from the polygon, but which doesn't alter the area of the polygon, gets removed.
I've completed all my tests and verified that all automated tests succeed and that the 4 linked issues are solved by this PR as well. JIRA ticket CURA-7243 (no github issue) |
sine_polygons.simplify(length / 2, 2 * deviation); | ||
if (visualize) | ||
{ | ||
SVG svg("output/simplifySineLimitedError.svg", AABB(sine_before)); |
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.
There is a lot of code duplication with writing these svg files. I think we should convert it into a re-usable function
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.
Well. It's not like there's any complexity in the code. Nothing can go wrong. It would maybe be a bit cleaner.. Sure,
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.
Yeah, it's a bit nitpicking, but I like my code to be clean :)
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.
The conceptual load of reading the current code is no more, or perhaps even less than reading a new function which fits on one line. I don't think the physical length of the code should be a criterion to decide on code-cleanliness.
I think it is nitpicking. Let's not discuss. I would be okay with you fixing this, but I am overburdened atm.
* 2. Never remove a vertex if the distance between that vertex and the final resulting polygon would be higher than \p allowed_error_distance | ||
* 3. Simplify uses a heuristic and doesn't neccesarily remove all removable vertices under the above criteria. | ||
* 4. But simplify may never violate these criteria. | ||
* 5. Unless the segments or the distance is smaller than the rounding error of 5 micron |
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 confuses me. Does it refer to 4? (if so, it should be a part of 4) If not, I don't understand what it does refer to.
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.
Yes it refers to 4.
svg.nextLayer(); | ||
svg.writePolygon(zigzag, SVG::Color::RED); | ||
} | ||
EXPECT_THAT(zigzag.size(), testing::Eq(zigzag_before.size() - simplifiable_bend_count)) << "Should simplify bends with height 100 up to 500"; |
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.
That seems a bit light of a test, doesn't it? It's now only checking if the number of polygons is correct. Should there also not be some sort of test that actually checks if the error isn't too great?
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.
No. It's not checking zigzag_polygons
, it's checking the one polygon zigzag
.
Actually this test case is testing the most important thing atm. It only succeeds if exactly the number of bends which we expect to be dsimplified out actually do. No more and no less.
Yes. That's the whole goal of simplify(). |
Did you check the frontend PR for this PR?? The new simplify simplifies twice as hard as the old one, so I made a frontend PR to update all simplify settings to be halved. This also includes an upgrade system to update old profiles to new profiles with half the value. |
I've tested the basic functionality with a variety of organic and non-organic-but-rounded shapes and found no immediately visible concerns. The maximum resolution seems to be held in honour unless the maximum deviation is in concern. The maximum deviation seems to always be held in honour except for a minimum of 5 micrometres. Perhaps we want to set the minimum for Maximum Deviation in the front-end to 0.005mm? I have a cylinder with 100,000 sides with a radius of 10. (this one). That results in side lengths of 0.000314mm, or approximately 0.3 micrometres, so basically just multiple vertices on every integer coordinate possible along the circle. I sliced this using a maximum resolution and maximum deviation of 0.005mm, so that the exception for "pretty much straight" doesn't get in the way. Let's take an inset of 0.175mm into account for the outer wall line width. You'd expect then that a maximum deviation of 0.005mm can lead to side lengths of up to Here is a snippet of g-code that I took from around the middle of the height of the cylinder (since each face is also divided diagonally into 2 triangles).
I'm seeing distances here in the ballpark of 0.5mm, which is a bit lower than I'd expect but in the correct order of magnitude. I've also tested whether seams get removed from straight bits, which seems to work fine. I've also sliced this model with new and old (skin and infill removed to reduce noise from things that aren't simplified): It's not entirely immune against leaving in vertices in a straight line. Here's an example where it chose the wrong vertices to remove. It chose the diagonals of a flat face. Parameters are increased to make it visible: Bug CURA-7243 seems to be fixed. In general it's pretty hard to find faults with this. |
Did you guys look at the frontend changes? Ultimaker/Cura#7247 Im not sure whether it's easy to port these changes to a new version upgrade system for 4.7 instead of 4.6 |
Yes, I did. Like I said in my comparison:
I didn't apply the version upgrade in my tests, but I did use the new defaults to compare. To change the front-end for 4.7, we'd need to change the setting version there to 13 and rename the plug-in. It's not so hard. It does change those 1500 profiles again though. |
Ah ok. Good! |
I upgraded to 4.8 and re-sliced my model. It looks like the simplification changes were not made as planned by the developer. It got worse https://yadi.sk/i/oyUH92ART1Pteg |
That looks an awefull lot like coasting. Try disabling that. If that doesn't work, please create a new issue. |
Better tests for the simplify() function.
It is a very important function and the tests were flawed.
EDIT:
The tests proved that something was wrong with the function, and something was wrong with earlier tests.
Therefore I had to rewrite and fix simplify()
Thanks to @smartavionics for laying down the ground work for this PR.