diff --git a/kikit/intervals.py b/kikit/intervals.py index 1e2cbffa..c8da29a2 100644 --- a/kikit/intervals.py +++ b/kikit/intervals.py @@ -326,7 +326,21 @@ def collectHardStops(boxes: Iterable[Box]) -> Tuple[List[AxialLine], List[AxialL def defaultSeedFilter(boxIdA: object, boxIdB: object, vertical: bool, seedline: AxialLine) -> bool: return True -def collectSeedLines(boxes: Dict[object, Box], seedFilter: Callable[[object, object, bool, AxialLine], bool]) \ +def getSeedLinePosition(a: float, b: float, isAGhost: bool, isBGhost: bool) -> float: + """ + Given two points, and an indication if they belong to a "ghost" box, + return the point where to put the seed line. + + If both are ghosts, or both are not ghosts, the seed is the midpoint, + otherwise it is the ghost point. + """ + if isAGhost == isBGhost: + return (a + b) / 2 + elif isAGhost: + return a + return b + +def collectSeedLines(boxes: Dict[object, Box], seedFilter: Callable[[object, object, bool, AxialLine], bool], ghosts: set[int]=set()) \ -> Tuple[List[AxialLine], List[AxialLine]]: """ Given a dictionary ident -> box return a list of all midlines between @@ -336,6 +350,8 @@ def collectSeedLines(boxes: Dict[object, Box], seedFilter: Callable[[object, obj serves as a predicate that can filter unwanted seed lines - e.g., too far apart or comming from ghost boxes. + The ghosts parameter is a set containing the IDs of all "ghost" boxes. + Returns (horlines, verlines), where the lines are tagged with ident """ neighbors = BoxNeighbors(boxes) @@ -343,25 +359,29 @@ def collectSeedLines(boxes: Dict[object, Box], seedFilter: Callable[[object, obj verlines: List[AxialLine] = [] for identA, boxA in boxes.items(): for identB, shadow in neighbors.leftC(identA): - mid = (boxA[0] + boxes[identB][2]) / 2 + mid = getSeedLinePosition(boxA[0], boxes[identB][2], + identA in ghosts, identB in ghosts) candidates = [AxialLine(mid, e.min, e.max, identA) for e in shadow.intervals] verlines.extend([x for x in candidates if seedFilter(identA, identB, True, x)]) for identB, shadow in neighbors.rightC(identA): - mid = (boxA[2] + boxes[identB][0]) / 2 + mid = getSeedLinePosition(boxA[2], boxes[identB][0], + identA in ghosts, identB in ghosts) candidates = [AxialLine(mid, e.min, e.max, identA) for e in shadow.intervals] verlines.extend([x for x in candidates if seedFilter(identA, identB, True, x)]) for identB, shadow in neighbors.topC(identA): - mid = (boxA[1] + boxes[identB][3]) / 2 + mid = getSeedLinePosition(boxA[1], boxes[identB][3], + identA in ghosts, identB in ghosts) candidates = [AxialLine(mid, e.min, e.max, identA) for e in shadow.intervals] horlines.extend([x for x in candidates if seedFilter(identA, identB, False, x)]) for identB, shadow in neighbors.bottomC(identA): - mid = (boxA[3] + boxes[identB][1]) / 2 + mid = getSeedLinePosition(boxA[3], boxes[identB][1], + identA in ghosts, identB in ghosts) candidates = [AxialLine(mid, e.min, e.max, identA) for e in shadow.intervals] horlines.extend([x for x in candidates @@ -480,7 +500,7 @@ class BoxPartitionLines: def __init__(self, boxes: Dict[object, Box], seedFilter: Callable[[object, object, bool, AxialLine], bool]=defaultSeedFilter, - safeHorizontalMargin: float=0, safeVerticalMargin: float=0) -> None: + safeHorizontalMargin: float=0, safeVerticalMargin: float=0, ghosts: set[int]=set()) -> None: """ Given a dictionary id -> box initializes the structure. @@ -488,13 +508,15 @@ def __init__(self, boxes: Dict[object, Box], The margin guarantees there will be no partition line too close to edge (necessary to handle some pathological cases) + + The ghosts parameter is a set containing the IDs of all "ghost" boxes. """ from kikit.common import shpBBoxExpand hstops, vstops = collectHardStops(boxes.values()) hSafeStops, vSafeStops = collectHardStops([ shpBBoxExpand(x, safeVerticalMargin, safeHorizontalMargin) for x in boxes.values()]) - hseeds, vseeds = collectSeedLines(boxes, seedFilter) + hseeds, vseeds = collectSeedLines(boxes, seedFilter, ghosts) hshadows = buildShadows(hseeds, chain(vstops, vSafeStops)) vshadows = buildShadows(vseeds, chain(hstops, hSafeStops)) diff --git a/kikit/panelize_ui_impl.py b/kikit/panelize_ui_impl.py index ca270f3c..cf6cc427 100644 --- a/kikit/panelize_ui_impl.py +++ b/kikit/panelize_ui_impl.py @@ -418,13 +418,13 @@ def dummyFramingSubstrate(substrates, preset): # algorithm (as there is no distinguishion between left and right side) width = fromMm(1) if vSpace is not None: - top = box(minx, miny - 2 * vSpace - width, maxx, miny - 2 * vSpace) - bottom = box(minx, maxy + 2 * vSpace, maxx, maxy + 2 * vSpace + width) + top = box(minx, miny - vSpace - width, maxx, miny - vSpace) + bottom = box(minx, maxy + vSpace, maxx, maxy + vSpace + width) dummy.append(polygonToSubstrate(top)) dummy.append(polygonToSubstrate(bottom)) if hSpace is not None: - left = box(minx - 2 * hSpace - width, miny, minx - 2 * hSpace, maxy) - right = box(maxx + 2 * hSpace, miny, maxx + 2 * hSpace + width, maxy) + left = box(minx - hSpace - width, miny, minx - hSpace, maxy) + right = box(maxx + hSpace, miny, maxx + hSpace + width, maxy) dummy.append(polygonToSubstrate(left)) dummy.append(polygonToSubstrate(right)) return dummy diff --git a/kikit/substrate.py b/kikit/substrate.py index b1026e9d..f944c548 100644 --- a/kikit/substrate.py +++ b/kikit/substrate.py @@ -1086,9 +1086,8 @@ def seedFilter(idA, idB, v, l): return False return idA not in ghosts or idB not in ghosts self._partition = BoxPartitionLines( - self._preprocessBoxes(boxes), - seedFilter, - safeHorizontalMargin, safeVerticalMargin) + self._preprocessBoxes(boxes), seedFilter, + safeHorizontalMargin, safeVerticalMargin, ghosts) def _preprocessBoxes(self, boxes): """