Avoid changing scan path when stripping segments with duplicate positions#33
Avoid changing scan path when stripping segments with duplicate positions#33MattRolchigo wants to merge 2 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adjusts toolpath event generation/deduplication to prevent start-of-layer “power-off” dwells from being stripped and to avoid scan-path modifications caused by overly aggressive duplicate-position collapsing.
Changes:
- Perturbs the x-position of the initial “power-off” entry added at the start of each layer to keep it from being removed as a duplicate location.
- Updates
strip_duplicate_locationsso only consecutive dwells are merged; non-dwell duplicates are preserved by perturbing x to maintain event separation.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # This entry is as the same position as the one after it | ||
| # If both entries are dwells, they can be combined | ||
| # Otherwise, combining entries will change the scan path itself | ||
| # To avoid this, slightly perturb the position rather than combining entries | ||
| # This is necessary as adamantine cannot handle consecutive entries with the same position | ||
| if entry[2] != 0 or out[-1][2] != 0: | ||
| # Slightly perturb x position | ||
| modified_position = (entry[1][0] + eps, entry[1][1], entry[1][2]) | ||
| modified_entry = (entry[0], modified_position, entry[2]) | ||
| # Append this modified event | ||
| out.append(modified_entry) |
There was a problem hiding this comment.
When two consecutive entries share the same position and one is a dwell (power==0) while the other is powered (power!=0), this logic always perturbs the earlier entry. That can end up perturbing powered scan points (e.g., where a powered point is immediately followed by a power-off point at the same location in the input layer files), which contradicts the goal of avoiding scan-path changes under power. Consider instead perturbing the dwell entry (power==0) regardless of ordering (which may require modifying out[-1] instead of entry when the dwell is the later element).
| # This entry is as the same position as the one after it | |
| # If both entries are dwells, they can be combined | |
| # Otherwise, combining entries will change the scan path itself | |
| # To avoid this, slightly perturb the position rather than combining entries | |
| # This is necessary as adamantine cannot handle consecutive entries with the same position | |
| if entry[2] != 0 or out[-1][2] != 0: | |
| # Slightly perturb x position | |
| modified_position = (entry[1][0] + eps, entry[1][1], entry[1][2]) | |
| modified_entry = (entry[0], modified_position, entry[2]) | |
| # Append this modified event | |
| out.append(modified_entry) | |
| # This entry is at the same position as the one after it | |
| # If both entries are dwells, they can be combined (by dropping one) | |
| # Otherwise, combining entries will change the scan path itself | |
| # To avoid this, slightly perturb the position rather than combining entries. | |
| # This is necessary as adamantine cannot handle consecutive entries with the same position. | |
| # Prefer perturbing a dwell (power == 0) rather than a powered point. | |
| if entry[2] == 0 and out[-1][2] == 0: | |
| # Both entries are dwells: combine by keeping only the later one in time (already in out) | |
| # Do not append the earlier dwell entry. | |
| continue | |
| elif entry[2] == 0 and out[-1][2] != 0: | |
| # Current entry is a dwell and the later entry is powered: perturb this dwell | |
| modified_position = (entry[1][0] + eps, entry[1][1], entry[1][2]) | |
| modified_entry = (entry[0], modified_position, entry[2]) | |
| out.append(modified_entry) | |
| elif entry[2] != 0 and out[-1][2] == 0: | |
| # Current entry is powered and the later entry is a dwell: perturb the dwell in-place | |
| prev_time, prev_pos, prev_power = out[-1] | |
| modified_position = (prev_pos[0] + eps, prev_pos[1], prev_pos[2]) | |
| out[-1] = (prev_time, modified_position, prev_power) | |
| # Append the powered entry unchanged | |
| out.append(entry) | |
| else: | |
| # Both entries are powered: perturb the earlier entry as before | |
| modified_position = (entry[1][0] + eps, entry[1][1], entry[1][2]) | |
| modified_entry = (entry[0], modified_position, entry[2]) | |
| out.append(modified_entry) |
There was a problem hiding this comment.
It doesn't matter which entry or entries get perturbed, since the perturbation is small enough as to not affect the scan path. As long as consecutive entries do not have the same position, it is fine.
| else: | ||
| # This entry is as the same position as the one after it | ||
| # If both entries are dwells, they can be combined | ||
| # Otherwise, combining entries will change the scan path itself | ||
| # To avoid this, slightly perturb the position rather than combining entries | ||
| # This is necessary as adamantine cannot handle consecutive entries with the same position | ||
| if entry[2] != 0 or out[-1][2] != 0: | ||
| # Slightly perturb x position | ||
| modified_position = (entry[1][0] + eps, entry[1][1], entry[1][2]) | ||
| modified_entry = (entry[0], modified_position, entry[2]) | ||
| # Append this modified event | ||
| out.append(modified_entry) |
There was a problem hiding this comment.
Because duplicates are resolved in a single reverse pass, perturbing an entry to avoid a scan/dwell collision can prevent earlier consecutive dwells from being combined. Example pattern: dwell@P, dwell@P, scan@P will perturb the second dwell (to avoid matching the scan) and then the first dwell no longer matches it, so the two dwells are not combined and an extra micro-move is introduced during power-off time. To ensure only consecutive dwells are combined, consider collapsing adjacent dwell runs (power==0) at identical positions before applying the non-dwell perturbation rule (or do a forward pass that handles dwell/dwell first).
There was a problem hiding this comment.
A situation where multiple consecutive segments at the same location occur with non-zero and zero power would be rare, and whether or not the dwells are combined in such a case won't affect the overall result as the applied perturbation to the location is minor to begin with
Previously, the short dwells added to the start of each layer would be stripped from the scan path, as they have the same x,y,z position as the subsequent segment. The modification to
add_power_off_entryslightly perturbs the x position of these entries to avoid being stripped.The modification to
strip_duplicate_locationsensures that only consecutive dwells are combined, as combining multiple scan segments or combining scan segments with dwells will modify the scan path itself (could remove dwells or change the beam velocity between events). This is again accomplished by slightly perturbing the x positions of events.