@pad is applied unconditionally wherever tile bounds are computed, so a caller can get the padded bounds or nothing. There is no way to ask a padded plan for the tile's own (unpadded) bounds short of mutating @pad and putting it back, or recomputing the grid arithmetic by hand.
Sites that bake it in:
# R/freeTilePlan.R:145
p <- x@pad
bounds <- cbind(x@bounds[, 1L] - p, x@bounds[, 2L] + p,
x@bounds[, 3L] - p, x@bounds[, 4L] + p)
# R/spatialTilePlan.R:232
p <- x@pad; e <- x@extent
bounds <- cbind(e[[1L]] + (j_idx - 1L) * w - p, e[[1L]] + j_idx * w + p,
e[[3L]] + (i_idx - 1L) * h - p, e[[3L]] + i_idx * h + p)
# R/intersect.R:91, 97, 120, 133 — same, for selection
getTile() takes a pad argument, but it is additive (tiles <- tiles + pad), so it cannot subtract the plan's own padding either.
Why it matters
Any algorithm where the halo exists for reading but ownership belongs to the tile proper needs both bounds from one plan:
- padded bounds → the data to load, so results near the edge are correct
- core bounds → which items this tile is responsible for, so neighbouring tiles do not both claim the same item
Without the second, overlapping tiles double-count. The immediate case is chunked motif enumeration (GiottoDisk#72): a tile needs a k-1 hop halo or subgraphs spanning the boundary are lost, but a subgraph must be counted by exactly one tile — the one holding its root. Same shape as any haloed convolution, watershed, or neighbour-count pass.
Today the caller has to reach past the API:
core <- tp; core@pad <- 0 # mutate a copy and hope nothing else reads it
sel_core <- intersect(core, query)
sel_halo <- intersect(tp, query)
Suggested shape
Something injectable rather than a second slot — a .CORE sentinel or a core = TRUE switch threaded through as.polygons(), intersect() and getTile(), so one plan answers both questions without being copied or mutated:
as.polygons(tp) # padded, unchanged default
as.polygons(tp, core = TRUE) # the tile itself
intersect(tp, query) # tiles whose padded bounds hit the query
intersect(tp, query, core = TRUE) # tiles whose own bounds hit it
The information is already there in every one of those functions — p is in scope at each site and the unpadded form is the same expression with p = 0. This is an accessor gap, not a computation gap.
Applies to spatialTilePlan, freeTilePlan and pixelTilePlan alike, since all three carry pad on the shared tilePlan base.
@padis applied unconditionally wherever tile bounds are computed, so a caller can get the padded bounds or nothing. There is no way to ask a padded plan for the tile's own (unpadded) bounds short of mutating@padand putting it back, or recomputing the grid arithmetic by hand.Sites that bake it in:
getTile()takes apadargument, but it is additive (tiles <- tiles + pad), so it cannot subtract the plan's own padding either.Why it matters
Any algorithm where the halo exists for reading but ownership belongs to the tile proper needs both bounds from one plan:
Without the second, overlapping tiles double-count. The immediate case is chunked motif enumeration (GiottoDisk#72): a tile needs a
k-1hop halo or subgraphs spanning the boundary are lost, but a subgraph must be counted by exactly one tile — the one holding its root. Same shape as any haloed convolution, watershed, or neighbour-count pass.Today the caller has to reach past the API:
Suggested shape
Something injectable rather than a second slot — a
.COREsentinel or acore = TRUEswitch threaded throughas.polygons(),intersect()andgetTile(), so one plan answers both questions without being copied or mutated:The information is already there in every one of those functions —
pis in scope at each site and the unpadded form is the same expression withp = 0. This is an accessor gap, not a computation gap.Applies to
spatialTilePlan,freeTilePlanandpixelTilePlanalike, since all three carrypadon the sharedtilePlanbase.