Raw File
wingeom.S
#
#	wingeom.S	Various geometrical computations in windows
#
#
#	$Revision: 4.21 $	$Date: 2007/03/16 08:52:59 $
#
#
#
#
#-------------------------------------
area.owin <- function(w) {
	verifyclass(w, "owin")
        # area may be precomputed
        if(!is.null(w$area))
          return(w$area)
        switch(w$type,
               rectangle = {
		width <- abs(diff(w$xrange))
		height <- abs(diff(w$yrange))
		area <- width * height
               },
               polygonal = {
                 area <- sum(unlist(lapply(w$bdry, area.xypolygon)))
               },
               mask = {
                 pixelarea <- abs(w$xstep * w$ystep)
                 npixels <- sum(w$m)
                 area <- pixelarea * npixels
               },
               stop("Unrecognised window type")
        )
        return(area)
}

eroded.areas <- function(w, r) {
	verifyclass(w, "owin")
	
	switch(w$type,
               rectangle = {
                 width <- abs(diff(w$xrange))
                 height <- abs(diff(w$yrange))
                 areas <- pmax(width - 2 * r, 0) * pmax(height - 2 * r, 0)
               },
               polygonal = {
                 # warning("Approximating polygonal window by digital image")
                 w <- as.mask(w)
                 areas <- eroded.areas(w, r)
               },
               mask = {
                 # distances from each pixel to window boundary
                 b <- bdist.pixels(w, coords=FALSE)
                 # histogram breaks to satisfy hist()
                 Bmax <- max(b, r)
                 breaks <- c(-1,r,Bmax+1)
                 # histogram of boundary distances
                 h <- hist(b, breaks=breaks, plot=FALSE)$counts
                 # reverse cumulative histogram
                 H <- revcumsum(h)
                 # drop first entry corresponding to r=-1
                 H <- H[-1]
                 # convert count to area
                 pixarea <- w$xstep * w$ystep
                 areas <- pixarea * H
               },
 	       stop("unrecognised window type")
               )
	areas
}	

even.breaks.owin <- function(w) {
	verifyclass(w, "owin")
        Rmax <- diameter(w)
        make.even.breaks(Rmax, Rmax/(100 * sqrt(2)))
}

unit.square <- function() { owin(c(0,1),c(0,1)) }

square <- function(r=1) {
  if(length(r) != 1 || !is.numeric(r))
    stop("argument r must be a single number")
  if(is.na(r) || !is.finite(r))
    stop("argument r is NA or infinite")
  if(r <= 0)
    stop("side of square must be positive")
  owin(c(0,r),c(0,r))
}

overlap.owin <- function(A, B) {
  # compute the area of overlap between two windows
  At <- A$type
  Bt <- B$type
  if(At=="rectangle" && Bt=="rectangle") {
    xmin <- max(A$xrange[1],B$xrange[1])
    xmax <- min(A$xrange[2],B$xrange[2])
    if(xmax <= xmin) return(0)
    ymin <- max(A$yrange[1],B$yrange[1])
    ymax <- min(A$yrange[2],B$yrange[2])
    if(ymax <= ymin) return(0)
    return((xmax-xmin) * (ymax-ymin))
  }
  if((At=="rectangle" && Bt=="polygonal")
     || (At=="polygonal" && Bt=="rectangle")
     || (At=="polygonal" && Bt=="polygonal"))
  {
    AA <- as.polygonal(A)$bdry
    BB <- as.polygonal(B)$bdry
    area <- 0
    for(i in seq(AA))
      for(j in seq(BB))
        area <- area + overlap.xypolygon(AA[[i]], BB[[j]])
    return(area)
  }
  if(At=="mask") {
    # count pixels in A that belong to B
    pixelarea <- abs(A$xstep * A$ystep)
    x <- as.vector(raster.x(A)[A$m])
    y <- as.vector(raster.y(A)[A$m])
    ok <- inside.owin(x, y, B) 
    return(pixelarea * sum(ok))
  }
  if(Bt== "mask") {
    # count pixels in B that belong to A
    pixelarea <- abs(B$xstep * B$ystep)
    x <- as.vector(raster.x(B)[B$m])
    y <- as.vector(raster.y(B)[B$m])
    ok <- inside.owin(x, y, A)
    return(pixelarea * sum(ok))
  }
  stop("Internal error")
}

#
#
#  Intersection and union of windows
#
#
intersect.owin <- function(A, B, ...) {
  verifyclass(A, "owin")
  verifyclass(B, "owin")

  if(identical(A, B))
    return(A)

  Arect <- (A$type == "rectangle")
  Brect <- (B$type == "rectangle")
  Amask <- (A$type == "mask")
  Bmask <- (B$type == "mask")
  
  # determine intersection of x and y ranges
  xr <- intersect.ranges(A$xrange, B$xrange)
  yr <- intersect.ranges(A$yrange, B$yrange)
  C <- owin(xr, yr)

  # rectangular case
  if(Arect && Brect)
    return(C)

  # Trim any existing masks to the intersection of the two ranges
  if(Amask)
    A <- trim.mask(A, C)
  if(Bmask)
    B <- trim.mask(B, C)

  # Did the user specify the pixel raster?
  if(length(list(...)) > 0) {
    # convert to masks with specified parameters, and intersect
    if(Amask) {
      A <- as.mask(A, ...)
      return(restrict.mask(A, B))
    } else {
      B <- as.mask(B, ...)
      return(restrict.mask(B, A))
    }
  } 
  
  # One mask and one rectangle?
  if(Arect && Bmask)
      return(B)
  if(Amask && Brect)
      return(A)

  # One mask and one polygon?
  if(Amask && !Bmask) 
    return(restrict.mask(A, B))
  if(!Amask && Bmask)
    return(restrict.mask(B, A))

  # Two existing masks?
  if(Amask && Bmask) {
    # choose the finer one
    if(A$xstep <= B$xstep)
      return(restrict.mask(A, B))
    else
      return(restrict.mask(B, A))
  }
  
  # No existing masks.
  # Convert A to a mask with default pixel raster, and intersect.
  A <- as.mask(A)
  return(restrict.mask(A, B))
}


union.owin <- function(A, B, ...) {
  verifyclass(A, "owin")
  verifyclass(B, "owin")

  if(identical(A, B))
    return(A)

  if(A$type == "rectangle" && B$type == "rectangle") {
    if(is.subset.owin(A, B))
      return(B)
    else if (is.subset.owin(B,A))
      return(A)
  }

  C <- owin(range(A$xrange, B$xrange),
            range(A$yrange, B$yrange))

  Amask <- (A$type == "mask")
  Bmask <- (B$type == "mask")

  # Determine pixel raster parameters
  rasterinfo <- 
    if((length(list(...)) > 0))
      list(...)
    else if(Amask)
      list(xy=list(x=prolongseq(A$xcol, C$xrange),
                   y=prolongseq(A$yrow, C$yrange)))
    else if(Bmask)
      list(xy=list(x=prolongseq(B$xcol, C$xrange),
                   y=prolongseq(B$yrow, C$yrange)))
    else
      list()

  # Convert C to mask
  C <- do.call("as.mask", append(list(w=C), rasterinfo))
      
  x <- as.vector(raster.x(C))
  y <- as.vector(raster.y(C))
  ok <- inside.owin(x, y, A) | inside.owin(x, y, B)

  if(!any(ok))
    stop("Internal error: union is empty")

  if(!all(ok))
    C$m[] <- ok

  return(C)
}

# auxiliary functions
  
trim.mask <- function(M, R) {
    # M is a mask,
    # R is a rectangle inside bounding.box(M)
    # Extract subset of image grid
    within.range <- function(u, v) { (u >= v[1]) & (u <= v[2]) }
    yrowok <- within.range(M$yrow, R$yrange)
    xcolok <- within.range(M$xcol, R$xrange)
    if(sum(yrowok) == 0 || sum(xcolok) == 0)
      stop("result is empty")
    Z <- M
    Z$xrange <- R$xrange
    Z$yrange <- R$yrange
    Z$yrow <- M$yrow[yrowok]
    Z$xcol <- M$xcol[xcolok]
    Z$m <- M$m[yrowok, xcolok]
    Z$dim <- dim(Z$m)
    return(Z)
}

restrict.mask <- function(M, W) {
  # M is a mask, W is any window
  stopifnot(inherits(M, "owin") && M$type == "mask")
  stopifnot(inherits(W, "owin"))
  if(W$type == "rectangle")
    return(trim.mask(M, W))
  # Determine which pixels of M are inside W
  Mm <- M$m
  x <- as.vector(raster.x(M)[Mm])
  y <- as.vector(raster.y(M)[Mm])
  ok <- inside.owin(x, y, W)
  Mm[Mm] <- ok
  M$m <- Mm
  return(M)
}
  
expand.owin <- function(W, f=1) {
  # expand bounding box of 'win'
  # by factor 'f' in **area**
  if(f <= 0)
    stop("f must be > 0")
  if(f == 1)
    return(W)
  bb <- bounding.box(W)
  xr <- bb$xrange
  yr <- bb$yrange
  fff <- (sqrt(f) - 1)/2
  Wexp <- owin(xr + fff * c(-1,1) * diff(xr),
               yr + fff * c(-1,1) * diff(yr))
  return(Wexp)
}

trim.rectangle <- function(W, xmargin=0, ymargin=xmargin) {
  if(W$type != "rectangle")
    stop("Internal error: tried to trim margin off non-rectangular window")
  if(length(xmargin) == 1)
    xmargin <- rep(xmargin, 2)
  if(length(ymargin) == 1)
    ymargin <- rep(ymargin, 2)
  if(any(xmargin < 0) || any(ymargin < 0))
    stop("values of xmargin, ymargin must be nonnegative")
  if(sum(xmargin) > diff(W$xrange))
    stop("window is too small to cut off margins of the width specified")
  if(sum(ymargin) > diff(W$yrange))
    stop("window is too small to cut off margins of the height specified")
  owin(W$xrange + c(1,-1) * xmargin,
       W$yrange + c(1,-1) * ymargin)
}


bdry.mask <- function(W) {
  verifyclass(W, "owin")
  W <- as.mask(W)
  m <- W$m
  nr <- nrow(m)
  nc <- ncol(m)
  b <-     (m != rbind(FALSE,       m[-nr, ]))
  b <- b | (m != rbind(m[-1, ], FALSE))
  b <- b | (m != cbind(FALSE,       m[, -nc]))
  b <- b | (m != cbind(m[, -1], FALSE))
  W$m <- b
  return(W)
}

vertices <- function(w) {
  verifyclass(w, "owin")
  switch(w$type,
         rectangle={
           xr <- w$xrange
           yr <- w$yrange
           vert <- list(x=xr[c(1,2,2,1)], y=yr[c(1,1,2,2)])
         },
         polygonal={
           vert <- do.call("concatxy",w$bdry)
         },
         mask={
           b <- bdry.mask(w)
           xx <- raster.x(w)
           yy <- raster.y(w)
           vert <- list(x=as.vector(xx[b$m]),
                        y=as.vector(yy[b$m]))
         })
  return(vert)
}

diameter <- function(w) {
  vert <- vertices(w)
  d <- pairdist(vert)
  return(max(d))
}

back to top