Fix/fill bed objects over plate boundary - #885
Open
muhammetfurkandemiral wants to merge 9 commits into
Open
muhammetfurkandemiral wants to merge 9 commits into
muhammetfurkandemiral wants to merge 9 commits into
Conversation
Right-clicking an object and picking "Fill bed with copies" left copies laid over the plate boundary, raising "An object is laid over the plate boundaries". After packing, libnest2d's finalAlign() re-centers the pile on the convex hull of the packed items. That hull ignores the fixed items that filling the bed always leaves around (other objects, the wipe tower, excluded regions), so the shift it computes can push copies off the plate. BBS hit this and turned the alignment off for their own vendor (STUDIO-3265), but `!is_bbl` kept it on for everyone else. Turn it off unconditionally. Besides removing the bad shift, Alignment::DONT_ALIGN makes the placer's boundaryCheck a strict isInside(chull, bin) test instead of an overfit penalty, so items are only packed when they really fit the bin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… objects Above 100 copies FillBedJob skips the arranger and drops the copies into the grid cells returned by Plater::get_empty_cells(). Three things went wrong there: - ArrangePolygon::translation positions the instance origin, but the cell is sized around the object's convex hull. When the origin is not the hull center every copy is displaced by that delta and the outer row hangs off the plate. - The cell pitch was measured on the unrotated outline, so a copy carrying a Z rotation has a larger footprint than the cell it was given. - get_empty_cells() grids the raw build volume. It knows neither the skirt/brim margin already applied to m_bedpts nor the objects standing on the plate, so copies could land over the edge or on top of an existing object. Measure the footprint on the rotated outline, seat each copy on its cell by that footprint, and test every cell before using it: a copy that does not fit the shrunk bed or that overlaps an unselected item is skipped and the next cell is tried. get_empty_cells() works in the current plate's coordinates while m_bedpts and m_unselected are normalized to the first plate, so the plate offset is applied before comparing, the same way finalize() does it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Fill bed with copies" packs copies right up to the bed edge, so the outermost ones land inside the 3.5 mm band the plater checks for spiral lift collisions, and "Model too close to bed boundary. Disable spiral lifting or keep at least 3.5mm gap to avoid collision." appears the moment the command finishes. Running Arrange afterwards clears it only because arrange centers the pile and happens to leave a margin, which is luck rather than intent. Shrink the arranged bed by SPIRAL_LIFT_SAFETY_MARGIN whenever any filament's Z hop performs a spiral lift, so arrange and fill bed both leave the gap on their own. "Auto Lift" counts as a spiral lift here because GCode.cpp resolves it to one when it writes the G-code. The margin constant moves next to ZHopType instead of staying a local constexpr inside the plater check, so the check and the arranger cannot drift apart. Sequential printing is left alone: its clearance_radius model governs spacing there, and folding the margin in would fight it. FillBedJob's >100-copy grid fallback bypasses the arranger, but the previous commit made it test its cells against the shrunk bed, so the margin reaches that path as well. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…onfigured The "Model too close to bed boundary. Disable spiral lifting or keep at least 3.5mm gap to avoid collision." warning fired for every printable model near a rectangular plate edge, whatever Z hop the printer was set to. A user on Normal or Slope lift got told to disable a feature they were not using, over a risk that cannot occur: only a spiral lift traces an arc outside the object footprint, which is the whole reason for the margin. Gate the check on the same predicate the arranger uses, so the warning appears exactly when the hazard does. The config is resolved once per call instead of per volume, from the plater's cached config rather than rebuilding a full one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…of objects Slicing a full plate of tall models with a prime tower ended in "A G-code path goes beyond the plate boundaries", with the offending path in the tower. Every non-BBL printer is sliced with WipeTower2, which lays down a stabilization cone under the tower whose radius is tan(cone_angle / 2) * tower_height - it widens as the print gets taller. Print::first_layer_wipe_tower_corners() already extrudes that cone, but the GUI never accounted for it: - The code that keeps the tower on the plate before slicing bounded only the width x depth rectangle plus brim, so a tower parked near an edge passed that check and then spilled over once its cone was sliced. - get_wipe_tower_info(), which arrange and fill bed treat as the tower, used the same rectangle, so copies were packed right up against where the cone lands. Add WipeTower2::get_first_layer_footprint(), the bounding box of that first layer (rectangle, brim and cone), and use it in both places. With a zero cone angle - and always on BBL printers, whose WipeTower has no such cone - it is the old rectangle-plus-brim bound, so their behaviour is unchanged. get_wipe_tower_info() also bounded the tower position as if its box started at the origin (clamp to [0, plate - size]), although the box already reached below it by twice the brim. Near the far edge that shifted arrange's idea of the tower away from where it really stood, and would have done so by the whole cone once the box covered it. Bound the position by the box's own min and max instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ter's "Prime Tower" was rendered as "Başbakan Kulesi" - prime as in prime minister - in the prime tower collision warning. Use "Prime Kulesi", the term the rest of the Turkish translation already uses for "Prime tower". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fill bed packed the copies around the prime tower wherever it had been left. A tower standing mid-plate, or a little off an edge, splits the free area and wastes the strip beside it, which is the opposite of what filling the plate is for. Before packing, the tower is now pushed into the plate corner nearest to it - nearest, so a tower placed back-left stays back-left - with its whole first-layer footprint (brim and stabilization cone) WIPE_TOWER_MARGIN inside the plate, and the copies are packed around it there. If the footprint does not fit the plate either way the tower is left for the plate clamp to deal with. The position is written to the project config directly: the tower info carries a plate-local position, whereas WipeTowerInfo::apply_wipe_tower() subtracts the plate origin as if it were a world one, which would misplace the tower on every plate but the first. Plain Arrange still leaves the tower where the user put it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A new "Fill bed: 3 options" item in the object's right-click menu fills three
new plates with copies of the selected object, each packed with a different
trade-off between how many copies fit and how much room each gets, so they can
be compared side by side and the preferred plate printed:
- A Max copies may be rotated, no extra gap or edge margin
- B Balanced no rotation, 3 mm extra gap between copies, 2 mm along the edge
- C Safe no rotation, 8 mm extra gap, 5 mm along the edge
Every gap sits on top of the brim / support aware inflation the arranger gives
each copy anyway, so support room is never traded for count, and the spiral
lift margin from update_arrange_params() still applies. Each plate is named
after its option and copy count ("A Max - 16 copies").
The source object is left where it is. On a multi-material print the new plates
get the prime tower pushed into the corner nearest to where the current plate
has it, the copies packed around its full first-layer footprint. To reserve that
spot without moving the current plate's tower, the corner snap is split from
storing the position: get_wipe_tower_corner_arrangepoly() only computes it.
All plates are created before any copy is placed, because a new plate can
re-flow the plate grid and move the origins of the plates already there. Copies
are placed at their plate's origin and registered with it. More than 100 copies
per option would make the packer crawl, so an option is capped there and its
plate is named "100+". Plates that would exceed MAX_PLATES_COUNT are skipped
with a notification, and so is an object that does not fit an empty plate.
Turkish strings for the new UI are added.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Fill bed: 3 options" named its plates correctly ("B Balanced - 14 copies")
but every copy stood on the same spot in the middle of the plate, raising the
collision warning.
The copies were registered with their plate through add_to_plate(), which
calls PartPlate::add_instance() with move_position set and so moves a newly
added instance to the plate centre - after its packed position had already
been applied.
Register them with notify_instance_update(..., is_new) instead: it finds the
plate the instance stands on and adds it there without moving it, as the
instances path of fill bed does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Screenshots/Recordings/Graphs
Tests