Raw File
#
#  psp.R
#
#  $Revision: 1.29 $ $Date: 2007/10/24 09:41:15 $
#
# Class "psp" of planar line segment patterns
#
#
#################################################
# creator
#################################################
psp <- function(x0, y0, x1, y1, window, marks=NULL) {
  stopifnot(is.numeric(x0))
  stopifnot(is.numeric(y0))
  stopifnot(is.numeric(x1))
  stopifnot(is.numeric(y1))
  stopifnot(is.vector(x0))
  stopifnot(is.vector(y0))
  stopifnot(is.vector(x1))
  stopifnot(is.vector(y1))
  stopifnot(length(x0) == length(y0))
  stopifnot(length(x1) == length(y1))
  stopifnot(length(x0) == length(x1))
  ends <- data.frame(x0=x0,y0=y0,x1=x1,y1=y1)
  window <- as.owin(window)
  if(!is.null(marks)) {
    if(is.data.frame(marks))
      stop("Sorry, data frames of marks are not implemented for psp objects")
    stopifnot(is.vector(marks))
    stopifnot(length(marks) == length(x0))
  }
  out <- list(ends=ends,
              window=window,
              n = nrow(ends),
              marks = marks)
  class(out) <- c("psp", class(out))
  return(out)
}

######################################################
#  conversion
######################################################

as.psp <- function(x, ..., from=NULL, to=NULL) {
  # special case: two point patterns
  if(is.null(from) != is.null(to))
    stop(paste("If one of", sQuote("from"), "and", sQuote("to"),
               "is specified, then both must be specified"))
  if(!is.null(from) && !is.null(to)) {
    verifyclass(from, "ppp")
    verifyclass(to, "ppp")
    if(from$n != to$n)
      stop(paste("point patterns", sQuote("from"), "and", sQuote("to"),
                 "have different numbers of points"))
    uni <- union.owin(from$window, to$window)
    Y <- do.call("psp",
                 resolve.defaults(list(from$x, from$y, to$x, to$y),
                                  list(...),
                                  list(window=uni)))
    return(Y)
  }
  UseMethod("as.psp")
}

as.psp.psp <- function(x, ..., fatal=TRUE) {
  if(!verifyclass(x, "psp", fatal=fatal))
    return(NULL)
  ends <- x$ends
  psp(ends$x0, ends$y0, ends$x1, ends$y1, window=x$window, marks=x$marks)
}

as.psp.data.frame <- function(x, ..., window=NULL, marks=NULL, fatal=TRUE) {
  if(checkfields(x, c("x0", "y0", "x1", "y1")))
    return(psp(x$x0, x$y0, x$x1, x$y1, window=window, marks=marks))
  else if(checkfields(x, c("xmid", "ymid", "length", "angle"))) {
    dx <- cos(x$angle) * x$length/2
    dy <- sin(x$angle) * x$length/2
    return(psp(x$x - dx, x$y - dy, x$x + dx, x$y + dy,
                window=window, marks=marks))
  }
  else if(ncol(x) == 4)
    return(psp(x[,1], x[,2], x[,3], x[,4], window=window, marks=marks))
  else if(fatal)
    stop("Unable to interpret x as a line segment pattern")
  return(NULL)
}

as.psp.matrix <- function(x, ..., window=NULL, marks=NULL, fatal=TRUE) {
  if(ncol(x) == 4)
    return(psp(x[,1], x[,2], x[,3], x[,4], window=window, marks=marks))
  else if(fatal)
    stop("Unable to interpret x as a line segment pattern")
  return(NULL)
}

as.psp.default <- function(x, ..., window=NULL, marks=NULL, fatal=TRUE) {
  if(checkfields(x, c("x0", "y0", "x1", "y1")))
    return(psp(x$x0, x$y0, x$x1, x$y1, window=window, marks=marks))
  else if(checkfields(x, c("xmid", "ymid", "length", "angle"))) {
    dx <- cos(x$angle) * x$length/2
    dy <- sin(x$angle) * x$length/2
    return(psp(x$x - dx, x$y - dy, x$x + dx, x$y + dy,
                window=window, marks=marks))
  }
  else if(fatal)
    stop("Unable to interpret x as a line segment pattern")
  return(NULL)
}

as.psp.owin <- function(x, ..., fatal=TRUE) {
  verifyclass(x, "owin")
  # can't use as.rectangle here; still testing validity
  xframe <- owin(x$xrange, x$yrange)
  switch(x$type,
         rectangle = {
           xx <- x$xrange[c(1,2,2,1)]
           yy <- x$yrange[c(1,1,2,2)]
           nxt <- c(2,3,4,1)
           out <- psp(xx, yy, xx[nxt], yy[nxt], window=x)
           return(out)
         },
         polygonal = {
           x0 <- y0 <- x1 <- y1 <- numeric(0)
           bdry <- x$bdry
           for(i in seq(bdry)) {
             po <- bdry[[i]]
             ni <- length(po$x)
             nxt <- c(2:ni, 1)
             x0 <- c(x0, po$x)
             y0 <- c(y0, po$y)
             x1 <- c(x1, po$x[nxt])
             y1 <- c(y1, po$y[nxt])
           }
           out <- psp(x0, y0, x1, y1,  window=xframe)
           return(out)
         },
         mask = {
           if(fatal) stop("x is a mask")
           else warning("x is a mask - no line segments returned")
           return(psp(numeric(0), numeric(0), numeric(0), numeric(0),
                      window=xframe))
         })
  return(NULL)
}


append.psp <- function(A,B) {
  verifyclass(A, "psp")
  verifyclass(B, "psp")
  stopifnot(identical(A$window, B$window))
  result <- list(ends=rbind(A$ends, B$ends),
                 window=A$window,
                 n=A$n + B$n,
                 marks=c(marks(A), marks(B)))
  class(result) <- c("psp", class(result))
  return(result)
}

rebound.psp <- function(x, ...) {
  verifyclass(x, "psp")
  x$window <- rebound.owin(x$window, ...)
  return(x)
}


marks.psp <- function(x, ..., dfok=FALSE) {
  # data frames of marks are not implemented for psp
  return(x$marks)
}

markformat.psp <- function(x) {
  # data frames of marks are not implemented for psp
  return(if(!is.null(marks(x))) "vector" else "none")
}

#################################################
#  plot and print methods
#################################################

plot.psp <- function(x, ..., add=FALSE) {
  verifyclass(x, "psp")
  if(!add) {
    do.call.matched("plot.owin", 
                    resolve.defaults(list(x=x$window),
                                     list(...),
                                     list(main=deparse(substitute(x)))))
  }
  if(!is.null(marks(x, dfok=TRUE)))
    warning("marks are currently ignored in plot.psp")
  if(x$n > 0)
    do.call.matched("segments", append(as.list(x$ends), list(...)))
  return(invisible(NULL))
}

print.psp <- function(x, ...) {
  verifyclass(x, "psp")
  cat(paste("planar line segment pattern:",
            x$n, "line segments\n"))
  print(x$window)
  marx <- marks(x, dfok=FALSE)
  if(!is.null(marx))
    cat(paste("Marks vector of type", sQuote(typeof(marx)), "\n"))
  return(invisible(NULL))
}

unitname.psp <- function(x) {
  return(unitname(x$window))
}

"unitname<-.psp" <- function(x, value) {
  w <- x$window
  unitname(w) <- value
  x$window <- w
  return(x)
}

####################################################
#    summary information
####################################################

endpoints.psp <- function(x, which="both") {
  verifyclass(x, "psp")
  ends <- x$ends
  n <- x$n
  switch(which,
         both={
           first <- second <- rep(TRUE, n)
         },
         first={
           first <- rep(TRUE, n)
           second <- rep(FALSE, n)
         },
         second={
           first <- rep(FALSE, n)
           second <- rep(TRUE, n)
         },
         left={
           first <- (ends$x0 < ends$x1)
           second <- !first
         },
         right={
           first <- (ends$x0 > ends$x1)
           second <- !first
         },
         lower={
           first <- (ends$y0 < ends$y1)
           second <- !first
         },
         upper={
           first <- (ends$y0 > ends$y1)
           second <- !first
         },
         stop(paste("Unrecognised option: which=", sQuote(which)))
         )
  ok <- rbind(first, second)
  xmat <- rbind(ends$x0, ends$x1)
  ymat <- rbind(ends$y0, ends$y1)
  idmat <- col(ok)
  xx <- as.vector(xmat[ok])
  yy <- as.vector(ymat[ok])
  id <- as.vector(idmat[ok])
  result <- ppp(xx, yy, window=x$window, check=FALSE)
  attr(result, "id") <- id
  return(result)
}

midpoints.psp <- function(x) {
  verifyclass(x, "psp")
  xm <- eval(expression((x0+x1)/2), envir=x$ends)
  ym <- eval(expression((y0+y1)/2), envir=x$ends)
  win <- x$window
  ok <- inside.owin(xm, ym, win)
  if(any(!ok)) {
    warning(paste("Some segment midpoints lie outside the original window;",
                  "window replaced by bounding box"))
    win <- bounding.box(win)
  }
  ppp(x=xm, y=ym, window=win, check=FALSE)
}

lengths.psp <- function(x) {
  verifyclass(x, "psp")
  eval(expression(sqrt((x1-x0)^2 + (y1-y0)^2)), envir=x$ends)
}

angles.psp <- function(x, directed=FALSE) {
  verifyclass(x, "psp")
  a <- eval(expression(atan2(y1-y0, x1-x0)), envir=x$ends)
  if(!directed) 
    a <- a %% pi
  return(a)
}

summary.psp <- function(object, ...) {
  verifyclass(object, "psp")
  len <- lengths.psp(object)
  out <- list(n = object$n,
              len = summary(len),
              totlen = sum(len),
              ang= summary(angles.psp(object)),
              w = summary.owin(object$window),
              marks=if(is.null(object$marks)) NULL else summary(object$marks),
              unitinfo=summary(unitname(object)))
  class(out) <- c("summary.psp", class(out))
  return(out)
}

print.summary.psp <- function(x, ...) {
  cat(paste(x$n, "line segments\n"))
  cat("Lengths:\n")
  print(x$len)
  unitblurb <- paste(x$unitinfo$plural, x$unitinfo$explain)
  cat(paste("Total length:", x$totlen, unitblurb, "\n"))
  cat(paste("Length per unit area:", x$totlen/x$w$area, "\n"))
  cat("Angles (radians):\n")
  print(x$ang)
  print(x$w)
  if(!is.null(x$marks)) {
    cat("Marks:\n")
    print(x$marks)
  }
  return(invisible(NULL))
}

  
########################################################
#  subsets
########################################################

"[.psp" <-
"subset.psp" <-
  function(x, i, j, drop, ...) {

    verifyclass(x, "psp")
    
    if(missing(i) && missing(j))
      return(x)
        
    if(!missing(i)) {
      style <- if(inherits(i, "owin")) "window" else "index"
      switch(style,
             window={
               x <- clip.psp(x, window=i)
             },
             index={
               subset <- i
               marktype <- markformat(x)
               x <- as.psp(x$ends[subset, ],
                           window=x$window,
                           marks=switch(marktype,
                             none=NULL,
                             vector=x$marks[subset],
                             dataframe=x$marks[subset,]))
             })
    }

    if(!missing(j))
      x <- x[j] # invokes code above
    
    return(x)
 }
  


####################################################
# affine transformations
####################################################

affine.psp <- function(X,  mat=diag(c(1,1)), vec=c(0,0), ...) {
  verifyclass(X, "psp")
  W <- affine.owin(X$window, mat=mat, vec=vec)
  E <- X$ends
  ends0 <- affinexy(list(x=E$x0,y=E$y0), mat=mat, vec=vec)
  ends1 <- affinexy(list(x=E$x1,y=E$y1), mat=mat, vec=vec)
  psp(ends0$x, ends0$y, ends1$x, ends1$y, window=W, marks=marks(X, dfok=TRUE))
}

shift.psp <- function(X, vec=c(0,0), ...) {
  verifyclass(X, "psp")
  W <- shift.owin(X$window, vec=vec, ...)
  E <- X$ends
  ends0 <- shiftxy(list(x=E$x0,y=E$y0), vec=vec, ...)
  ends1 <- shiftxy(list(x=E$x1,y=E$y1), vec=vec, ...)
  psp(ends0$x, ends0$y, ends1$x, ends1$y, window=W, marks=marks(X, dfok=TRUE))
}

rotate.psp <- function(X, angle=pi/2, ...) {
  verifyclass(X, "psp")
  W <- rotate.owin(X$window, angle=angle, ...)
  E <- X$ends
  ends0 <- rotxy(list(x=E$x0,y=E$y0), angle=angle, ...)
  ends1 <- rotxy(list(x=E$x1,y=E$y1), angle=angle, ...)
  psp(ends0$x, ends0$y, ends1$x, ends1$y, window=W, marks=marks(X, dfok=TRUE))
}


back to top