Skip to content

Bug 17148: debug rasterImage orientation on Windows #142

@hturner

Description

@hturner

Reprex

The following code takes a 4x4 raster image, oriented with x increasing left to right and y increasing bottom to top. This is plotted in the top right. The image is then rotated by angle and then three more versions of the two rasters are created:

top-left: flipping x-axis
bottom-left: flipping x-axis and y-axis
bottom right: flipping y-axis

Functions for reprex - source these first
get_rotated_corners <- function(
        xleft,
        ybottom,
        xright,
        ytop,
        x_rotate_center,
        y_rotate_center,
        angle_degree
) {
    sgn <- sign(xright - xleft)*sign(ytop - ybottom)
    angle_rad <- (angle_degree * pi / 180) * sgn
    
    # Calculate initial corner points
    corners_x <- c(xleft, xright, xright, xleft)
    corners_y <- c(ybottom, ybottom, ytop, ytop)
    
    # Calculate rotated corner points
    rotated_corners_x <- numeric(4)
    rotated_corners_y <- numeric(4)
    
    for (i in 1:4) {
        # Translate to origin
        x_translated <- corners_x[i] - x_rotate_center
        y_translated <- corners_y[i] - y_rotate_center
        
        # Rotate
        x_rotated <- x_translated * cos(angle_rad) - y_translated * sin(angle_rad)
        y_rotated <- x_translated * sin(angle_rad) + y_translated * cos(angle_rad)
        
        # Translate back
        rotated_corners_x[i] <- x_rotated + x_rotate_center
        rotated_corners_y[i] <- y_rotated + y_rotate_center
    }
    
    return(list(rotated_corners_x,rotated_corners_y))
}

raster4 <- function(starting_image, ending_image = starting_image,
                    angle = 20) {
    
    op <- par(bg = "thistle", mar = rep(2.5, 4)); on.exit(par(op))
    
    plot(1:10, type = "n", main = names(dev.cur()), asp = 1)
    mtext(R.version.string, cex = 0.75)
    abline(h = c(2, 4, 7, 9), lty = 2)
    abline(v = c(2, 4, 7, 9), lty = 2)
    
    # TOP LEFT
    
    ## Axes
    ### xleft to xright (allowing extra for arrow)
    arrows(x0 = 4, y0 = 7, x1 = 1.25, y1 = 7, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(1.5, 6.5, labels = "x", cex = 1)
    ### ybottom to ytop (allowing extra for arrow) 
    arrows(x0 = 4, y0 = 7, x1 = 4, y1 = 9.75, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(4.5, 9.5, labels = "y", cex = 1)
    
    ## Original top left square
    rasterImage(starting_image, xleft = 4, ybottom = 7, xright = 2, ytop = 9, angle = 0, interpolate = FALSE)
    rect(xleft = 4, ybottom = 7, xright = 2, ytop = 9, border = "black")
    
    ## Rotated top left square
    sgn <- sign(2 - 4)*sign(9 - 7) # negative if only one axes in negative direction
    rasterImage(ending_image, xleft = 4, ybottom = 7, xright = 2, ytop = 9, angle = angle*sgn, interpolate = FALSE)
    rotated_corners_top_left <- get_rotated_corners(
        xleft = 4, ybottom = 7, xright = 2, ytop = 9, # can I swap xleft and xright here?
        x_rotate_center = 4,
        y_rotate_center = 7,
        angle_degree = angle
    )
    polygon(rotated_corners_top_left[[1]], rotated_corners_top_left[[2]], border = "black")
    
    ## Rotation point of top left square
    points(4, 7, col = "green", pch = 16, cex = 1)
    
    # TOP RIGHT
    
    ## Axes
    ### xleft to xright (allowing extra for arrow)
    arrows(x0 = 7, y0 = 7, x1 = 9.75, y1 = 7, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(9.5, 6.5, labels = "x", cex = 1)
    ### ybottom to ytop (allowing extra for arrow) 
    arrows(x0 = 7, y0 = 7, x1 = 7, y1 = 9.75, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(6.5, 9.5, labels = "y", cex = 1)
    
    ## Original top right square
    rasterImage(starting_image, xleft = 7, ybottom = 7, xright = 9, ytop = 9, angle = 0, interpolate = FALSE)
    rect(xleft = 7, ybottom = 7, xright = 9, ytop = 9, border = "black")
    
    ## Rotated top right square
    sgn <- sign(9 - 7)*sign(9 - 7) # negative if only one axes in negative direction
    rasterImage(ending_image, xleft = 7, ybottom = 7, xright = 9, ytop = 9, angle = angle*sgn, interpolate = FALSE)
    rotated_corners_top_right <- get_rotated_corners(
        xleft = 7, ybottom = 7, xright = 9, ytop = 9,
        x_rotate_center = 7,
        y_rotate_center = 7,
        angle_degree = angle
    )
    polygon(rotated_corners_top_right[[1]], rotated_corners_top_right[[2]], border = "black")
    
    ## Rotation point of top right square
    points(7, 7, col = "green", pch = 16, cex = 1)
    
    # BOTTOM LEFT
    
    ## Axes
    ### xleft to xright (allowing extra for arrow)
    arrows(x0 = 4, y0 = 4, x1 = 1.25, y1 = 4, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(1.5, 4.5, labels = "x", cex = 1)
    ### ybottom to ytop (allowing extra for arrow) 
    arrows(x0 = 4, y0 = 4, x1 = 4, y1 = 1.25, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(4.5, 1.5, labels = "y", cex = 1)
    
    ## Original bottom left square
    rasterImage(starting_image, xleft = 4, ybottom = 4, xright = 2, ytop = 2, angle = 0, interpolate = FALSE)
    rect(xleft = 4, ybottom = 4, xright = 2, ytop = 2, border = "black")
    
    ## Rotated bottom left square
    sgn <- sign(2 - 4)*sign(2 - 4) # negative if only one axes in negative direction
    rasterImage(ending_image, xleft = 4, ybottom = 4, xright = 2, ytop = 2, angle = angle*sgn, interpolate = FALSE)
    rotated_corners_bottom_left <- get_rotated_corners(
        xleft = 4, ybottom = 4, xright = 2, ytop = 2,
        x_rotate_center = 4,
        y_rotate_center = 4,
        angle_degree = angle
    )
    polygon(rotated_corners_bottom_left[[1]], rotated_corners_bottom_left[[2]], border = "black")
    
    ## Rotation point of bottom left square
    points(4, 4, col = "green", pch = 16, cex = 1)
    
    # BOTTOM RIGHT
    
    ## Axes
    ### xleft to xright (allowing extra for arrow)
    arrows(x0 = 7, y0 = 4, x1 = 9.75, y1 = 4, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(9.5, 4.5, labels = "x", cex = 1)
    ### ybottom to ytop (allowing extra for arrow) 
    arrows(x0 = 7, y0 = 4, x1 = 7, y1 = 1.25, length = 0.15, angle = 30,
           code = 2, lwd = 2)
    text(6.5, 1.5, labels = "y", cex = 1)
    
    ## Original bottom right square
    rasterImage(starting_image, xleft = 7, ybottom = 4, xright = 9, ytop = 2, angle=0, interpolate=FALSE)
    rect(7, 2, 9, 4, border = "black")
    
    ## Rotated bottom left square
    sgn <- sign(9 - 7)*sign(2 - 4) # negative if only one axes in negative direction
    rasterImage(ending_image, xleft = 7, ybottom = 4, xright = 9, ytop = 2, angle=angle*sgn, interpolate=FALSE)
    rotated_corners_bottom_right <- get_rotated_corners(
        xleft = 7, ybottom = 4, xright = 9, ytop = 2,
        x_rotate_center = 7,
        y_rotate_center = 4,
        angle_degree = angle
    )
    polygon(rotated_corners_bottom_right[[1]], rotated_corners_bottom_right[[2]], border = "black")
    
    ## Rotation point of bottom left square
    points(7, 4, col = "green", pch = 16, cex = 1)
    
    invisible(list(starting_image = starting_image, 
                   ending_image = ending_image, 
                   angle = angle))
    
}
f_start <- as.raster(rbind(
    c(0,  0,  0,  0),
    c(0, NA, NA, NA),
    c(0,  0,  0, NA),
    c(0, NA, NA, NA)
))
f_end <- as.raster(rbind(
    c(1,  1,  1,  1),
    c(1, NA, NA, NA),
    c(1,  1,  1, NA),
    c(1, NA, NA, NA)
))

raster4(f_start, f_end, angle = 20)

Expected result

This is the expected result which you get in Positron (with the ark graphics device) on in RStudio with the Cairo or AGG device (Tools > Global Options > General > Graphics > Backend):

Image

Result with windows device

On a windows device (open with windows() or change the backend in RStudio), you get:

Image

There are a couple of issues here:

  • The orientation (flipping) is correct, but the location and rotation is wrong.
  • Although the windows device can support transparency, the rotated raster is placed in a bounding box with a thistle background (the purple colour), obscuring parts of the plot that we should be able to see.

Task

The task is to debug plotting on the Windows device, to pin down where the code is wrong and how it might be fixed.

This requires Building R-Devel on Windows and debugging C code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CIssues requiring knowledge of CGraphicsIssues related to graphicsWindowsWindows GUI / Window specificneeds analysisTrack down the cause of the bug, or identify as not a bug

    Type

    No type

    Projects

    Status

    To Do

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions