From 9a9a05d1d797604ab707aec1382192cf0d0715ed Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 17 May 2021 00:55:38 -0700 Subject: [PATCH] add guillotine_bssf_sas --- masque/utils/pack2d.py | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/masque/utils/pack2d.py b/masque/utils/pack2d.py index 5d120ab..da1f397 100644 --- a/masque/utils/pack2d.py +++ b/masque/utils/pack2d.py @@ -105,3 +105,60 @@ def maxrects_bssf( regions = numpy.vstack((regions[~intersects], r_lft, r_bot, r_rgt, r_top)) return rect_locs, rejected_inds + + +def guillotine_bssf_sas(rect_sizes: numpy.ndarray, + regions: numpy.ndarray, + presort: bool = True, + allow_rejects: bool = True, + ) -> Tuple[numpy.ndarray, Set[int]]: + """ + sizes should be Nx2 + regions should be Mx4 (xmin, ymin, xmax, ymax) + #TODO: test me! + """ + rect_sizes = numpy.array(rect_sizes) + rect_locs = numpy.zeros_like(rect_sizes) + rejected_inds = set() + + if presort: + rotated_sizes = numpy.sort(rect_sizes, axis=0) # shortest side first + rect_order = numpy.lexsort(rotated_sizes.T)[::-1] # Descending shortest side + rect_sizes = rect_sizes[rect_order] + + for rect_ind, rect_size in enumerate(rect_sizes): + ''' Place the rect ''' + # Best short-side fit (bssf) to pick a region + bssf_scores = ((regions[:, 2:] - regions[:, :2]) - rect_size).min(axis=1).astype(float) + bssf_scores[bssf_scores < 0] = numpy.inf # doesn't fit! + rr = bssf_scores.argmin() + if numpy.isinf(bssf_scores[rr]): + if allow_rejects: + rejected_inds.add(rect_ind) + continue + else: + raise MasqueError(f'Failed to find a suitable location for rectangle {rect_ind}') + + # Read out location + loc = regions[rr, :2] + rect_locs[rect_ind] = loc + + region_size = regions[rr, 2:] - loc + split_horiz = region_size[0] < region_size[1] + + new_region0 = regions[rr].copy() + new_region1 = new_region0.copy() + split_vert = loc + rect_size + if split_horiz: + new_region0[2] = split_vert[0] + new_region0[1] = split_vert[1] + new_region1[0] = split_vert[0] + else: + new_region0[3] = split_vert[1] + new_region0[0] = split_vert[0] + new_region1[1] = split_vert[1] + + regions = numpy.vstack((regions[:rr], regions[rr + 1:], + new_region0, new_region1)) + + return rect_locs, rejected_inds