-
Notifications
You must be signed in to change notification settings - Fork 10
image/label transformations #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f90c91d
8e146c7
c13dbab
d77d514
b35dd2c
34ffa00
176f9fa
311d400
8e8d1f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -55,14 +55,60 @@ setMethod("scale", c("sdArray", "numeric"), \(x, j, t, ...) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # label ---- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #TODO | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #' @rdname trans | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #' @importFrom DelayedArray cbind rbind ConstantArray | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #' @importFrom methods as | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #' @export | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setMethod("translation", c("sdArray", "numeric"), \(x, t, ...) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #x <- label(sd, 2); t <- c(64,0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stopifnot( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length(t) == length(dim(x)), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t == round(t), all(is.finite(t))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+66
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length(t) == length(dim(x)), | |
| t == round(t), all(is.finite(t))) | |
| length(t) == length(dim(x)), | |
| all(t == round(t)), | |
| all(is.finite(t))) |
Copilot
AI
Apr 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When x is multiscale, ts is computed by multiplying t by scale factors derived from ncol(). This can yield non-integer translations due to non-integer scale ratios and/or floating-point rounding (e.g., 0.5 * t becoming 31.999999), which will later be used as array dimensions via abs(t[1/2]) and can error. Consider validating/rounding each scaled translation (and failing with a clear error if it’s not exactly integer) before using it to construct d.
| if (length(ys) == 1) { | |
| ts <- list(t) | |
| } else { | |
| ds <- vapply(ys, ncol, integer(1)) | |
| sf <- c(1, ds[-1]/ds[-length(ds)]) | |
| ts <- lapply(cumprod(sf), `*`, t) | |
| validate_translation <- \(tt, scale) { | |
| rr <- round(tt) | |
| tol <- sqrt(.Machine$double.eps) | |
| if (!all(is.finite(tt)) || any(abs(tt - rr) > tol)) { | |
| stop( | |
| sprintf( | |
| "translation becomes non-integer at multiscale level %d after scaling; got %s", | |
| scale, paste(tt, collapse=", ")), | |
| call.=FALSE) | |
| } | |
| as.integer(rr) | |
| } | |
| if (length(ys) == 1) { | |
| ts <- list(as.integer(round(t))) | |
| } else { | |
| ds <- vapply(ys, ncol, integer(1)) | |
| sf <- c(1, ds[-1]/ds[-length(ds)]) | |
| ts <- lapply(seq_along(sf), \(k) { | |
| validate_translation(cumprod(sf)[k] * t, k) | |
| }) |
Copilot
AI
Apr 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For 3D arrays you drop the first component of t (t <- t[-1]) and never use it. If a caller passes a non-zero translation for the first dimension, it will be silently ignored (and dim(y) will not match the requested translation). Either enforce t[1] == 0 when length(dim(y)) > 2, or implement translation along that dimension as well.
Copilot
AI
Apr 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.R() now returns the transpose of the usual CCW rotation matrix (suitable for right-multiplying row vectors, as used in ShapeFrame rotation via xy %*% .R(...)). However, PointFrame rotation computes x' = x*R[1,1] + y*R[1,2] / y' = x*R[2,1] + y*R[2,2] (left-multiplying column vectors), which makes the rotation direction opposite to ShapeFrame and the “counter-clockwise” comment. Please make the convention consistent (e.g., transpose R in the PointFrame method or adjust .R()/call sites) so the same angle rotates points in the same direction across element types.
| mutate(a=x*R[1,1], b=y*R[1,2]) |> | |
| mutate(c=x*R[2,1], d=y*R[2,2]) |> | |
| mutate(a=x*R[1,1], b=y*R[2,1]) |> | |
| mutate(c=x*R[1,2], d=y*R[2,2]) |> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Importing
cbind/rbindfrom DelayedArray into the package namespace can mask basecbind/rbindand affect other code paths in this package that callcbind()(e.g., data.frame/DFrame binding). Consider removing theseimportFrom()entries and instead callingDelayedArray::cbind()/DelayedArray::rbind()(orDelayedArray::bindCOLS/bindROWS) explicitly at the call sites that need DelayedArray support.