FormerLurker / ArcWelderLib

A collection of projects used to convert G0/G1 commands to G2/G3 commands.
364 stars 39 forks source link

Distance check should be per segment, not for an entire arc. #30

Open Protryon opened 3 years ago

Protryon commented 3 years ago

So, I've been copying some of the core logic for this project as a DXF welder for laser cutting/CNC machining from OpenSCAD.

One of the tweaks I've identified that is highly effective in maintaining accuracy, but making longer, sharper-angled arcs is to not track expected length for an entire arc-in-progress, but to calculate the nominal arc length for the angular distance between the last point on an arc and the next proposed point.

Diagram: aww-board

Right now we compare (abs((d1 + d2) - (d3 + d4)) < resolution) where resolution is something like 0.005.

I found from my testing this results in a lot of arcs not being formed. Removing this logic led to weird point inclusions due to distance, but coincidentally being in an "arc". I found a modified logic, using the same diagram as above: abs(d1 - d3) < resolution && abs(d3 - d4) < resolution. This maintains accuracy, but allows large or sharp arcs to properly form. To calculate d3 or d4, and presently they are calculated for the entire arc, I just modified some logic to get the angular difference from the two points of the corresponding segment.

See analogous removed logic: https://github.com/Protryon/dxf-welder/blob/main/src/dxf_process.rs#L160 Added logic: https://github.com/Protryon/dxf-welder/blob/main/src/dxf_process.rs#L221

FormerLurker commented 3 years ago

Very interesting, I will definitely dig into this.

I did want to mention that a few things have changed probably since you started working on your implementation:

  1. I've switched from using a fixed deviation (say in mm) from the original path and the arc path length to using a change percentage. I'm calling this the path tolerance percent. This seemed to be better at handling very small arcs and worked equally well when working on larger ones.
  2. This entire check was, as you noticed, to prevent very odd arcs from being generated from strange gcode. This was necessary because I didn't have a good way to determine how closely the generated arc matched the original path. However, I've created a new test that is very good at determining if the generated arc deviates too much from the original path.

It is debatable whether or not item 1 should still be implemented given that item 2 now exists. I've just pushed my (highly experimental and relatively messy/untested code) here, so you can take a look. The new check does a few things:

  1. It makes sure all points supplied are within the current slice of the full circle.
  2. It ensures each point rotates in the same direction.
  3. It makes sure that no segments connecting any points cross into the 'empty' part of the slice (the part that does not contain the arc).

There are a few gotchas here, but mostly dealing with item 2 above. When using polar coordinates, some arcs will cross 0, so direction testing isn't 100% straightforward. The key seemed to be detecting which arcs should cross 0 radians and using that as an additional criteria.

I'm still working this out and testing it. Also, the code I linked to (the 'late arc checking' branch) had some optimizations built into it that likely are not necessary, and increase the complexity of the algorithm too much. I'm going to be peeling this off and doing a refactor, so you may want to wait to examine the other parts until after I'm finished with that.

Let me know what you think!

FormerLurker commented 3 years ago

Ok, I fixed a typo and did some cleanup and have pushed the code I mentioned to the devel branch in case you would like to take a look.