improve docs and variable names
This commit is contained in:
parent
8f2f672137
commit
ecf37580c5
@ -17,8 +17,26 @@ def maxrects_bssf(
|
|||||||
allow_rejects: bool = True,
|
allow_rejects: bool = True,
|
||||||
) -> tuple[NDArray[numpy.float64], set[int]]:
|
) -> tuple[NDArray[numpy.float64], set[int]]:
|
||||||
"""
|
"""
|
||||||
sizes should be Nx2
|
Pack rectangles `rects` into regions `containers` using the "maximal rectangles best short side fit"
|
||||||
regions should be Mx4 (xmin, ymin, xmax, ymax)
|
algorithm (maxrects_bssf) from "A thousand ways to pack the bin", Jukka Jylanki, 2010.
|
||||||
|
|
||||||
|
This algorithm gives the best results, but is asymptotically slower than `guillotine_bssf_sas`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rects: Nx2 array of rectangle sizes `[[x_size0, y_size0], ...]`.
|
||||||
|
containers: Mx4 array of regions into which `rects` will be placed, specified using their
|
||||||
|
corner coordinates ` [[x_min0, y_min0, x_max0, y_max0], ...]`.
|
||||||
|
presort: If `True` (default), largest-shortest-side rectangles will be placed
|
||||||
|
first. Otherwise, they will be placed in the order provided.
|
||||||
|
allow_rejects: If `False`, `MasqueError` will be raised if any rectangle cannot be placed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
`[[x_min0, y_min0], ...]` placement locations for `rects`, with the same ordering.
|
||||||
|
The second argument is a set of indicies of `rects` entries which were rejected; their
|
||||||
|
corresponding placement locations should be ignored.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MasqueError if `allow_rejects` is `True` but some `rects` could not be placed.
|
||||||
"""
|
"""
|
||||||
regions = numpy.array(containers, copy=False, dtype=float)
|
regions = numpy.array(containers, copy=False, dtype=float)
|
||||||
rect_sizes = numpy.array(rects, copy=False, dtype=float)
|
rect_sizes = numpy.array(rects, copy=False, dtype=float)
|
||||||
@ -96,10 +114,30 @@ def guillotine_bssf_sas(
|
|||||||
allow_rejects: bool = True,
|
allow_rejects: bool = True,
|
||||||
) -> tuple[NDArray[numpy.float64], set[int]]:
|
) -> tuple[NDArray[numpy.float64], set[int]]:
|
||||||
"""
|
"""
|
||||||
sizes should be Nx2
|
Pack rectangles `rects` into regions `containers` using the "guillotine best short side fit with
|
||||||
regions should be Mx4 (xmin, ymin, xmax, ymax)
|
shorter axis split rule" algorithm (guillotine-BSSF-SAS) from "A thousand ways to pack the bin",
|
||||||
#TODO: test me!
|
Jukka Jylanki, 2010.
|
||||||
# TODO add rectangle-merge?
|
|
||||||
|
This algorithm gives the worse results than `maxrects_bssf`, but is asymptotically faster.
|
||||||
|
|
||||||
|
# TODO consider adding rectangle-merge?
|
||||||
|
# TODO guillotine could use some additional testing
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rects: Nx2 array of rectangle sizes `[[x_size0, y_size0], ...]`.
|
||||||
|
containers: Mx4 array of regions into which `rects` will be placed, specified using their
|
||||||
|
corner coordinates ` [[x_min0, y_min0, x_max0, y_max0], ...]`.
|
||||||
|
presort: If `True` (default), largest-shortest-side rectangles will be placed
|
||||||
|
first. Otherwise, they will be placed in the order provided.
|
||||||
|
allow_rejects: If `False`, `MasqueError` will be raised if any rectangle cannot be placed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
`[[x_min0, y_min0], ...]` placement locations for `rects`, with the same ordering.
|
||||||
|
The second argument is a set of indicies of `rects` entries which were rejected; their
|
||||||
|
corresponding placement locations should be ignored.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MasqueError if `allow_rejects` is `True` but some `rects` could not be placed.
|
||||||
"""
|
"""
|
||||||
regions = numpy.array(containers, copy=False, dtype=float)
|
regions = numpy.array(containers, copy=False, dtype=float)
|
||||||
rect_sizes = numpy.array(rects, copy=False, dtype=float)
|
rect_sizes = numpy.array(rects, copy=False, dtype=float)
|
||||||
@ -133,15 +171,15 @@ def guillotine_bssf_sas(
|
|||||||
|
|
||||||
new_region0 = regions[rr].copy()
|
new_region0 = regions[rr].copy()
|
||||||
new_region1 = new_region0.copy()
|
new_region1 = new_region0.copy()
|
||||||
split_vert = loc + rect_size
|
split_vertex = loc + rect_size
|
||||||
if split_horiz:
|
if split_horiz:
|
||||||
new_region0[2] = split_vert[0]
|
new_region0[2] = split_vertex[0]
|
||||||
new_region0[1] = split_vert[1]
|
new_region0[1] = split_vertex[1]
|
||||||
new_region1[0] = split_vert[0]
|
new_region1[0] = split_vertex[0]
|
||||||
else:
|
else:
|
||||||
new_region0[3] = split_vert[1]
|
new_region0[3] = split_vertex[1]
|
||||||
new_region0[0] = split_vert[0]
|
new_region0[0] = split_vertex[0]
|
||||||
new_region1[1] = split_vert[1]
|
new_region1[1] = split_vertex[1]
|
||||||
|
|
||||||
regions = numpy.vstack((regions[:rr], regions[rr + 1:],
|
regions = numpy.vstack((regions[:rr], regions[rr + 1:],
|
||||||
new_region0, new_region1))
|
new_region0, new_region1))
|
||||||
@ -157,19 +195,45 @@ def guillotine_bssf_sas(
|
|||||||
def pack_patterns(
|
def pack_patterns(
|
||||||
library: Mapping[str, Pattern],
|
library: Mapping[str, Pattern],
|
||||||
patterns: Sequence[str],
|
patterns: Sequence[str],
|
||||||
regions: numpy.ndarray,
|
containers: ArrayLike,
|
||||||
spacing: tuple[float, float],
|
spacing: tuple[float, float],
|
||||||
presort: bool = True,
|
presort: bool = True,
|
||||||
allow_rejects: bool = True,
|
allow_rejects: bool = True,
|
||||||
packer: Callable = maxrects_bssf,
|
packer: Callable = maxrects_bssf,
|
||||||
) -> tuple[Pattern, list[str]]:
|
) -> tuple[Pattern, list[str]]:
|
||||||
half_spacing = numpy.array(spacing) / 2
|
"""
|
||||||
|
Pick placement locations for `patterns` inside the regions specified by `containers`.
|
||||||
|
No rotations are performed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
library: Library from which `Pattern` objects will be drawn.
|
||||||
|
patterns: Sequence of pattern names which are to be placed.
|
||||||
|
containers: Mx4 array of regions into which `patterns` will be placed, specified using their
|
||||||
|
corner coordinates ` [[x_min0, y_min0, x_max0, y_max0], ...]`.
|
||||||
|
spacing: (x, y) spacing between adjacent patterns. Patterns are effectively expanded outwards
|
||||||
|
by `spacing / 2` prior to placement, so this also affects pattern position relative to
|
||||||
|
container edges.
|
||||||
|
presort: If `True` (default), largest-shortest-side rectangles will be placed
|
||||||
|
first. Otherwise, they will be placed in the order provided.
|
||||||
|
allow_rejects: If `False`, `MasqueError` will be raised if any rectangle cannot be placed.
|
||||||
|
packer: Bin-packing method; see the other functions in this module (namely `maxrects_bssf`
|
||||||
|
and `guillotine_bssf_sas`).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A `Pattern` containing one `Ref` for each entry in `patterns`.
|
||||||
|
A list of "rejected" pattern names, for which a valid placement location could not be found.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MasqueError if `allow_rejects` is `True` but some `rects` could not be placed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
half_spacing = numpy.array(spacing, copy=False, dtype=float) / 2
|
||||||
|
|
||||||
bounds = [library[pp].get_bounds() for pp in patterns]
|
bounds = [library[pp].get_bounds() for pp in patterns]
|
||||||
sizes = [bb[1] - bb[0] + spacing if bb is not None else spacing for bb in bounds]
|
sizes = [bb[1] - bb[0] + spacing if bb is not None else spacing for bb in bounds]
|
||||||
offsets = [half_spacing - bb[0] if bb is not None else (0, 0) for bb in bounds]
|
offsets = [half_spacing - bb[0] if bb is not None else (0, 0) for bb in bounds]
|
||||||
|
|
||||||
locations, reject_inds = packer(sizes, regions, presort=presort, allow_rejects=allow_rejects)
|
locations, reject_inds = packer(sizes, containers, presort=presort, allow_rejects=allow_rejects)
|
||||||
|
|
||||||
pat = Pattern()
|
pat = Pattern()
|
||||||
for pp, oo, loc in zip(patterns, offsets, locations):
|
for pp, oo, loc in zip(patterns, offsets, locations):
|
||||||
|
Loading…
Reference in New Issue
Block a user