polyCub/0000755000176000001440000000000012422436556011730 5ustar ripleyuserspolyCub/inst/0000755000176000001440000000000012422277200012672 5ustar ripleyuserspolyCub/inst/examples/0000755000176000001440000000000012422414264014513 5ustar ripleyuserspolyCub/inst/examples/polyCub.iso.R0000644000176000001440000000142012254673513017050 0ustar ripleyusers## we use the example polygon and f (exponential decay) from example(plotpolyf) ## numerical approximation of 'intrfr' (intISOnum <- polyCub.iso(letterR, f, center=fcenter)) ## analytical 'intrfr' (recall: f_r(r)=dexp(r), we need int_0^R r*f(r) dr) intrfr <- function (R, rate=1) pgamma(R, 2, rate) / rate (intISOana <- polyCub.iso(letterR, intrfr=intrfr, center=fcenter)) stopifnot(all.equal(intISOana, intISOnum, check.attributes=FALSE)) ### polygon area: f(r) = 1, f(x,y) = 1, center does not really matter intrfr.const <- function (R) R^2/2 (area.ISO <- polyCub.iso(letterR, intrfr=intrfr.const, center=c(0,0))) stopifnot(all.equal(spatstat::area.owin(letterR), area.ISO, check.attributes=FALSE)) ## the hole is subtracted correctly polyCub/inst/examples/polyCub.R0000644000176000001440000000324012411517117016251 0ustar ripleyusers### Short comparison of the various cubature methods ## 2D-function to integrate (here: isotropic zero-mean Gaussian density) f <- function (s, sigma = 5) exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2) ## simple polygonal integration domain disc.owin <- spatstat::disc(radius=5, centre=c(3,2), npoly=8) ## plot image of the function and integration domain plotpolyf(disc.owin, f, xlim=c(-8,8), ylim=c(-8,8)) ### Two-dimensional midpoint rule testmidpoint <- function (eps, main=paste("2D midpoint rule with eps =",eps)) { plotpolyf(disc.owin, f, xlim=c(-8,8), ylim=c(-8,8), use.lattice=FALSE) ## add evaluation points to plot with(spatstat::as.mask(disc.owin, eps=eps), points(expand.grid(xcol, yrow), col=m, pch=20)) polyCub.midpoint(disc.owin, f, eps=eps) } testmidpoint(5) testmidpoint(3) testmidpoint(0.5) testmidpoint(0.2) ### Product Gauss cubature using an increasing number of nodes for (nGQ in c(1:5,10,20,60)) { cat("nGQ =", sprintf("%2i",nGQ), ": ", format(polyCub.SV(disc.owin, f, nGQ=nGQ), digits=16), "\n") } ## 'rotation' affects location of nodes opar <- par(mfrow=c(1,2)) polyCub.SV(disc.owin, f, nGQ=2, rotation=FALSE, plot=TRUE) polyCub.SV(disc.owin, f, nGQ=2, rotation=TRUE, plot=TRUE) par(opar) ### Line integration along the boundary for isotropic functions polyCub.iso(disc.owin, f, center=c(0,0)) # see ?polyCub.iso ### Quasi-exact cubature of the bivariate Gaussian density ### using gpclib::tristrip and mvtnorm::pmvnorm() if (requireNamespace("mvtnorm") && gpclibPermit()) { print(polyCub.exact.Gauss(disc.owin, mean=c(0,0), Sigma=5^2*diag(2), plot=TRUE), digits=16) } polyCub/inst/examples/plotpolyf.R0000644000176000001440000000050312236701571016667 0ustar ripleyusers### a polygonal domain data("letterR", package="spatstat") ### f: isotropic exponential decay fr <- function(r, rate=1) dexp(r, rate=rate) fcenter <- c(2,3) f <- function (s, rate=1) fr(sqrt(rowSums(t(t(s)-fcenter)^2)), rate=rate) ### plot plotpolyf(letterR, f, use.lattice=FALSE) plotpolyf(letterR, f, use.lattice=TRUE) polyCub/inst/CITATION0000644000176000001440000000127712422277200014036 0ustar ripleyusers### list of authors authors <- c( SM = person("Sebastian", "Meyer"), LH = person("Leonhard", "Held"), MH = person("Michael", "H{\"o}hle") ) ### Outer header citHeader("To cite", sQuote("polyCub"), "in publications refer to Supplement B (Section 2.4) of:") ### power-law paper bibentry( bibtype = "Article", key = "Meyer+Held_2014", author = authors[c("SM", "LH")], title = "Power-law models for infectious disease spread", journal = "The Annals of Applied Statistics", issn = "1932-6157", year = "2014", volume = "8", number = "3", pages = "1612--1639", doi = "10.1214/14-AOAS743", eprint = "http://arxiv.org/abs/1308.5115" ) polyCub/inst/NEWS.Rd0000644000176000001440000001435312422414245013745 0ustar ripleyusers\newcommand{\CRANpkg}{\href{http://CRAN.R-project.org/package=#1}{\pkg{#1}}} %% some pre-defined commands: \R, \code, \acronym, \url, \file, \pkg \name{NEWS} \title{News for Package 'polyCub'} \section{Changes in polyCub version 0.5-1 (2014-10-24)}{ \itemize{ \item Nodes and weights for \code{polyCub.SV()} were only cached up to \code{nGQ=59}, not 60 as announced in version 0.5-0. Fixed that which also makes examples truly run without \pkg{statmod}. \item In \code{polyCub.SV()}, the new special setting \code{f=NULL} means to only compute nodes and weights. \item Internal changes to the \code{"gpc.poly"} converters to accommodate \CRANpkg{spatstat} 1.39-0. } } \section{Changes in polyCub version 0.5-0 (2014-05-07)}{ \itemize{ \item \code{polyCub.SV()} gained an argument \code{engine} to choose among available implementations. The new and faster C-implementation is the default. There should not be any numerical differences in the result of the cubature. \item Package \CRANpkg{statmod} is no longer strictly required (imported). Nodes and weights for Gauss-Legendre quadrature in \code{polyCub.SV()} are now cached in the \pkg{polyCub} package up to \code{nGQ=60}. \pkg{statmod}\code{::gauss.quad} is only queried for a higher number of nodes. } } \section{Changes in polyCub version 0.4-3 (2014-03-14)}{ \itemize{ \item \code{polyCub.iso()} ... \itemize{ \item could not handle additional arguments for \code{integrate()} given in the \code{control} list. \item applies the \code{control} arguments also to the numerical approximation of \code{intrfr}. } \item The \code{checkintrfr()} function is exported and documented. \item Added a \file{CITATION} file. } } \section{Changes in polyCub version 0.4-2 (2014-02-12)}{ \itemize{ \item \code{plotpolyf()} ... \itemize{ \item gained an additional argument \code{print.args}, an optional list of arguments passed to \code{print.trellis()} if \code{use.lattice=TRUE}. \item passed a \emph{data frame} of coordinates to \code{f} instead of a matrix as documented. } } } \section{Changes in polyCub version 0.4-1 (2013-12-05)}{ \itemize{ \item This version solely fixes a missing \file{NAMESPACE} import to make package \pkg{polyCub} again compatible with older versions of \CRANpkg{spatstat} (< 1.33-0). } } \section{Changes in polyCub version 0.4-0 (2013-11-19)}{ \subsection{INFRASTRUCTURE}{ \itemize{ \item \CRANpkg{rgeos} (and therefore the GEOS library) is no longer strictly required (moved from Imports to Suggests). \item Added \code{coerce}-methods from \code{"Polygons"} (or \code{"SpatialPolygons"} or \code{"Polygon"}) to \code{"owin"} (\code{as(..., "owin")}). \item \acronym{S4}-style \code{coerce}-methods between \code{"gpc.poly"} and \code{"Polygons"}/\code{"owin"} have been removed from the package (since we no longer import the formal class \code{"gpc.poly"} from \pkg{gpclib} or \pkg{rgeos}). However, there are two new functions \code{gpc2owin} and \code{owin2gpc} similar to those dropped from \CRANpkg{spatstat} since version 1.34-0. \item Moved \code{discpoly()} back to \CRANpkg{surveillance} since it is only used there. \item The latter two changes cause \CRANpkg{surveillance} version 1.6-0 to be incompatible with this new version of \pkg{polyCub}. Appropriate modifications have been made in the new version 1.7-0 of \pkg{surveillance}. } } \subsection{SPEED-UP \code{polyCub.SV()}}{ \itemize{ \item thorough optimization of \code{polyCub.SV()}-related code resulted in about 27\% speed-up: \itemize{ \item use \code{mapply()} instead of a \code{for}-loop \item avoid \code{cbind()} \item use \code{tcrossprod()} \item less object copying } } } \subsection{MINOR CHANGES}{ \itemize{ \item \code{xylist()} is now exported. It simply extracts polygon coordinates from various spatial classes (with same unifying intention as \code{xy.coords()}). \item A \code{polyregion} of class \code{"SpatialPolygons"} of length more than 1 now works in \code{polyCub}-methods. \item Use aspect ratio of 1 in \code{plotpolyf()}. } } } \section{Changes in polyCub version 0.3-1 (2013-08-22)}{ \itemize{ \item This version solely fixes a few typos and a technical note from \command{R CMD check} in the current R development version (also import packages into the \file{NAMESPACE} which are listed in the \dQuote{Depends:} field). } } \section{Changes in polyCub version 0.3-0 (2013-07-06)}{ \itemize{ \item New cubature method \code{polyCub.iso()} specific to isotropic functions (thanks to Emil Hedevang for the basic idea). \item New function \code{plotpolyf()} to plot a polygonal domain on top of an image of a bivariate function. \item The package now depends on \R >= 2.15.0 (for \code{.rowSums()}). \item The package no longer registers \code{"owin"} as an \acronym{S4}-class since we depend on the \pkg{sp} package which does the job. This avoids a spurious warning (in \code{.simpleDuplicateClass()}) upon package installation. \item In \code{discpoly()}, the argument \code{r} has been renamed to \code{radius}. This is backward compatible by partial argument matching in old code. } } \section{Changes in polyCub version 0.2-0 (2013-05-09)}{ \itemize{ \item This is the initial version of the \pkg{polyCub} package mainly built on functions previously maintained within the \CRANpkg{surveillance} package. These methods for cubature of polygonal domains have been outsourced into this separate \pkg{polyCub} package since they are of general use for other packages as well. \item The \pkg{polyCub} package has more documentation and tests, avoids the use of \CRANpkg{gpclib} as far as possible (using \CRANpkg{rgeos} instead), and solves a compatibility issue with package \CRANpkg{maptools} (use \code{setClass("owin")} instead of \code{setOldClass("owin")}). } } polyCub/tests/0000755000176000001440000000000012276665166013102 5ustar ripleyuserspolyCub/tests/testthat/0000755000176000001440000000000012422414264014722 5ustar ripleyuserspolyCub/tests/testthat/test-NWGL.R0000644000176000001440000000057712375634720016612 0ustar ripleyusers context("Validation of cached Gauss-Legendre nodes/weights") if (requireNamespace("statmod")) { test_that("statmod::gauss.quad() still gives the same result", { new.NWGL <- lapply(seq_len(61L), function (n) unname(statmod::gauss.quad(n = n, kind = "legendre"))) expect_that(new.NWGL, equals(.NWGL, check.attributes = FALSE)) }) } polyCub/tests/testthat/test-regression.R0000644000176000001440000000106212300426415020175 0ustar ripleyuserscontext("Regression tests") test_that("isotropic cubature can handle control list for integrate()", { data("letterR", package="spatstat", envir=environment()) f <- function (s) (rowSums(s^2)+1)^-2 ## previosly, passing control arguments did not work int1 <- polyCub.iso(letterR, f, center=c(0,0), control=list(rel.tol=1e-3)) int2 <- polyCub.iso(letterR, f, center=c(0,0), control=list(rel.tol=1e-8)) ## results are almost identical expect_that(int1, equals(int2, tolerance=1e-3)) expect_that(int1, not(is_identical_to(int2))) }) polyCub/tests/testthat/test-polyCub.R0000644000176000001440000000413312332416623017441 0ustar ripleyuserscontext("Correctness of cubature methods") ### set up test case ## bivariate, isotropic Gaussian density f <- function (s, mean, sd) dnorm(s[,1], mean=mean[1], sd=sd) * dnorm(s[,2], mean=mean[2], sd=sd) ## circular domain represented by a polygon r <- 5 center <- c(3,2) npoly <- 128 disc.owin <- spatstat::disc(radius=r, centre=center, npoly=npoly) ## parameters for f m <- c(1,1) sd <- 3 ## exact value of the integral over the _polygonal_ circle intExact <- 0.65844436 if (requireNamespace("mvtnorm") && gpclibPermit()) { ## run this conditionally since gpclib might not be available on all ## platforms (as pointed out by Uwe Ligges, 2014-04-20) test_that("polyCub.exact.Gauss returns validated result", { int <- polyCub.exact.Gauss(disc.owin, mean=m, Sigma=sd^2*diag(2)) expect_that(int, equals(intExact, tolerance=1e-8, check.attributes=FALSE)) }) } ### perform the tests (check against each other) test_that("polyCub.exact.Gauss and circleCub.Gauss give similar results", { ## exact value of the integral over the _real_ circle intExact_circle <- circleCub.Gauss(center=center, r=r, mean=m, sd=sd) ## how well this fits with the exact integral over a polyonal approximation ## of the circle depends of course on 'npoly' expect_that(intExact, equals(intExact_circle, tolerance=0.001, check.attributes=FALSE)) }) test_that("midpoint-cubature is correct", { int <- polyCub.midpoint(disc.owin, f, mean=m, sd=sd, dimyx=500) expect_that(int, equals(intExact, tolerance=0.001, check.attributes=FALSE)) }) test_that("SV-cubature is correct", { intC <- polyCub.SV(disc.owin, f, mean=m, sd=sd, nGQ=3, engine="C") intR <- polyCub.SV(disc.owin, f, mean=m, sd=sd, nGQ=3, engine="R") expect_that(intC, equals(intR)) expect_that(intC, equals(intExact, tolerance=0.0001, check.attributes=FALSE)) }) test_that("isotropic cubature is correct", { ## using a numerical approximation of intrfr int0 <- polyCub.iso(disc.owin, f, mean=m, sd=sd, center=m) expect_that(int0, equals(intExact, check.attributes=FALSE)) }) polyCub/tests/test-all.R0000644000176000001440000000014412276665166014751 0ustar ripleyusersif (packageVersion("testthat") >= "0.7.1.99") { library("testthat") test_check("polyCub") } polyCub/src/0000755000176000001440000000000012422414264012507 5ustar ripleyuserspolyCub/src/polyCub.SV.c0000644000176000001440000000576312422414264014632 0ustar ripleyusers/******************************************************************************* * Part of the R package "polyCub". * Free software under the terms of the GNU General Public License, version 2, * a copy of which is available at http://www.r-project.org/Licenses/. * * Copyright (C) 2014 Sebastian Meyer * Time-stamp: <[polyCub.SV.c] by SM Die 06/05/2014 21:39 (CEST)> * * C-version of .polygauss.side() ******************************************************************************/ void C_polygauss_side(double *x1, double *y1, double *x2, double *y2, double *s_loc, double *w_loc, double *s_N, double *w_N, double *alpha, int *loc, int *N, // lengths (loc is M=N+1 or N) // *loc * *N nodes and weights will be computed double *nodes_x, double *nodes_y, double *weights) { double half_pt_x = (*x1 + *x2) / 2.0; double half_length_x = (*x2 - *x1) / 2.0; double half_pt_y = (*y1 + *y2) / 2.0; double half_length_y = (*y2 - *y1) / 2.0; double x_gauss_side, y_gauss_side, scaling_fact_minus; int idx; for (int i = 0; i < *loc; i++) { // GAUSSIAN POINTS ON THE SIDE x_gauss_side = half_pt_x + half_length_x * s_loc[i]; y_gauss_side = half_pt_y + half_length_y * s_loc[i]; scaling_fact_minus = (x_gauss_side - *alpha) / 2.0; // COMPUTE NODES AND WEIGHTS for (int j = 0; j < *N; j++) { idx = j * *loc + i; // use same order as in R implementation nodes_x[idx] = *alpha + scaling_fact_minus * (s_N[j] + 1.0); nodes_y[idx] = y_gauss_side; weights[idx] = half_length_y*scaling_fact_minus * w_loc[i] * w_N[j]; } } } /*** * Function to be called from R to loop over all polygon edges, * calling the above C_polygauss_side() for each ***/ void C_polygauss( double *x, double *y, // vertex coordinates (open) of a polygon double *s_M, double *w_M, // nodes & weights of Gauss-Legendre quadrature double *s_N, double *w_N, // of degree M=N+1 and N, respectively double *alpha, // base-line int *L, int *M, int *N, // L: number of edges/vertices // result: nodes and weights of length (<=) M*N per edge double *nodes_x, double *nodes_y, double *weights ) { int idxTo, idxBlock; double x1, y1, x2, y2; for (int i = 0; i < *L; i++) { x1 = x[i]; y1 = y[i]; if (i == *L-1) idxTo = 0; else idxTo = i+1; x2 = x[idxTo]; y2 = y[idxTo]; // if edge is on base-line or is orthogonal to it -> skip if ((x1 == *alpha && x2 == *alpha) || (y2 == y1)) continue; idxBlock = i * *M * *N; // start index of nodes of edge i if (x2 == x1) // side is parallel to base-line -> use degree N in both dimensions C_polygauss_side(&x1, &y1, &x2, &y2, s_N, w_N, s_N, w_N, alpha, N, N, nodes_x + idxBlock, nodes_y + idxBlock, weights + idxBlock); else // use degrees M and N, respectively C_polygauss_side(&x1, &y1, &x2, &y2, s_M, w_M, s_N, w_N, alpha, M, N, nodes_x + idxBlock, nodes_y + idxBlock, weights + idxBlock); } } polyCub/NAMESPACE0000644000176000001440000000216412422163007013136 0ustar ripleyusers# Generated by roxygen2 (4.0.2): do not edit by hand S3method(xylist,Polygon) S3method(xylist,Polygons) S3method(xylist,SpatialPolygons) S3method(xylist,default) S3method(xylist,gpc.poly) S3method(xylist,owin) export(.polyCub.iso) export(checkintrfr) export(circleCub.Gauss) export(gpc2owin) export(gpclibPermit) export(gpclibPermitStatus) export(owin2gpc) export(plotpolyf) export(polyCub) export(polyCub.SV) export(polyCub.exact.Gauss) export(polyCub.iso) export(polyCub.midpoint) export(xylist) exportMethods(coerce) import(methods) import(sp) importFrom(grDevices,extendrange) importFrom(grDevices,gray) importFrom(grDevices,heat.colors) importFrom(grDevices,xy.coords) importFrom(graphics,image) importFrom(graphics,points) importFrom(graphics,polygon) importFrom(spatstat,as.im.function) importFrom(spatstat,as.polygonal) importFrom(spatstat,is.polygonal) importFrom(spatstat,owin) importFrom(spatstat,plot.im) importFrom(spatstat,plot.owin) importFrom(spatstat,summary.owin) importFrom(stats,cov2cor) importFrom(stats,dist) importFrom(stats,integrate) importFrom(stats,pchisq) importFrom(stats,pnorm) useDynLib(polyCub,C_polygauss) polyCub/R/0000755000176000001440000000000012422413074012117 5ustar ripleyuserspolyCub/R/polyCub.SV.R0000644000176000001440000003427012411524442014214 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2014 Sebastian Meyer ### Time-stamp: <[polyCub.SV.R] 2014-09-27 14:10 (CEST) by SM> ################################################################################ ##' Product Gauss Cubature over Polygonal Domains ##' ##' Product Gauss cubature over polygons as proposed by ##' Sommariva and Vianello (2007). ##' ##' @inheritParams plotpolyf ##' @param f a two-dimensional real function (or \code{NULL} to only compute ##' nodes and weights). ##' As its first argument it must take a coordinate matrix, i.e., a ##' numeric matrix with two columns, and it must return a numeric vector of ##' length the number of coordinates. ##' @param nGQ degree of the one-dimensional Gauss-Legendre quadrature rule ##' (default: 20) as implemented in function \code{\link[statmod]{gauss.quad}} ##' of package \pkg{statmod}. Nodes and weights up to \code{nGQ=60} are cached ##' in \pkg{polyCub}, for larger degrees \pkg{statmod} is required. ##' @param alpha base-line of the (rotated) polygon at \eqn{x = \alpha} (see ##' Sommariva and Vianello (2007) for an explication). If \code{NULL} (default), ##' the midpoint of the x-range of each polygon is chosen if no \code{rotation} ##' is performed, and otherwise the \eqn{x}-coordinate of the rotated point ##' \code{"P"} (see \code{rotation}). If \code{f} has its maximum value at the ##' origin \eqn{(0,0)}, e.g., the bivariate Gaussian density with zero mean, ##' \code{alpha = 0} is a reasonable choice. ##' @param rotation logical (default: \code{FALSE}) or a list of points ##' \code{"P"} and \code{"Q"} describing the preferred direction. If ##' \code{TRUE}, the polygon is rotated according to the vertices \code{"P"} and ##' \code{"Q"}, which are farthest apart (see Sommariva and Vianello, 2007). For ##' convex polygons, this rotation guarantees that all nodes fall inside the ##' polygon. ##' @param engine character string specifying the implementation to use. ##' Up to \pkg{polyCub} version 0.4-3, the two-dimensional nodes and weights ##' were computed by \R functions and these are still available by setting ##' \code{engine = "R"}. ##' The new C-implementation is now the default (\code{engine = "C"}) and ##' requires approximately 30\% less computation time.\cr ##' The special setting \code{engine = "C+reduce"} will discard redundant nodes ##' at (0,0) with zero weight resulting from edges on the base-line ##' \eqn{x = \alpha} or orthogonal to it. ##' This extra cleaning is only worth its cost for computationally intensive ##' functions \code{f} over polygons which really have some edges on the ##' baseline or parallel to the x-axis. Note that the old \R ##' implementation does not have such unset zero nodes and weights. ##' @param plot logical indicating if an illustrative plot of the numerical ##' integration should be produced. ##' @return The approximated value of the integral of \code{f} over ##' \code{polyregion}.\cr ##' In the case \code{f = NULL}, only the computed nodes and weights are ##' returned in a list of length the number of polygons of \code{polyregion}, ##' where each component is a list with \code{nodes} (a numeric matrix with ##' two columns), \code{weights} (a numeric vector of length ##' \code{nrow(nodes)}), the rotation \code{angle}, and \code{alpha}. ##' @author Sebastian Meyer\cr ##' The product Gauss cubature is based on the ##' original \acronym{MATLAB} implementation \code{polygauss} by Sommariva and ##' Vianello (2007), which is available under the GNU GPL (>=2) license from ##' \url{http://www.math.unipd.it/~alvise/software.html}. ##' @references ##' Sommariva, A. and Vianello, M. (2007). ##' Product Gauss cubature over polygons based on Green's integration formula. ##' \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. ##' @keywords math spatial ##' @family polyCub-methods ##' @importFrom graphics points ##' @examples # see example(polyCub) ##' @export polyCub.SV <- function (polyregion, f, ..., nGQ = 20, alpha = NULL, rotation = FALSE, engine = "C", plot = FALSE) { polys <- xylist(polyregion) # transform to something like "owin$bdry" # which means anticlockwise vertex order with # first vertex not repeated stopifnot(isScalar(nGQ), nGQ > 0, is.null(alpha) || (isScalar(alpha) && !is.na(alpha))) ## COMPUTE NODES AND WEIGHTS OF 1D GAUSS QUADRATURE RULE. ## DEGREE "N" (as requested) (ORDER GAUSS PRIMITIVE) nw_N <- gauss.quad(nGQ) ## DEGREE "M" = N+1 (ORDER GAUSS INTEGRATION) nw_M <- gauss.quad(nGQ + 1) ## Special case f=NULL: compute and return nodes and weights only if (is.null(f)) { return(lapply(X = polys, FUN = polygauss, nw_MN = c(nw_M, nw_N), alpha = alpha, rotation = rotation, engine = engine)) } ## Cubature over every single polygon of the "polys" list f <- match.fun(f) int1 <- function (poly) { nw <- polygauss(poly, c(nw_M, nw_N), alpha, rotation, engine) fvals <- f(nw$nodes, ...) cubature_val <- sum(nw$weights * fvals) ## if (!isTRUE(all.equal(0, cubature_val))) { ## if ((1 - 2 * as.numeric(poly$hole)) * sign(cubature_val) == -1) ## warning("wrong sign if positive integral") ## } cubature_val } respolys <- vapply(X=polys, FUN=int1, FUN.VALUE=0, USE.NAMES=FALSE) int <- sum(respolys) ### ILLUSTRATION ### if (plot) { plotpolyf(polys, f, ..., use.lattice=FALSE) for (i in seq_along(polys)) { nw <- polygauss(polys[[i]], c(nw_M, nw_N), alpha, rotation, engine) points(nw$nodes, cex=0.6, pch = i) #, col=1+(nw$weights<=0) } } ################### int } ## this wrapper provides a partially memoized version of ## unname(statmod::gauss.quad(n, kind="legendre")) gauss.quad <- function (n) { if (n <= 61) { # results cached in R/sysdata.rda .NWGL[[n]] } else if (requireNamespace("statmod")) { unname(statmod::gauss.quad(n = n, kind = "legendre")) } else { stop("package ", sQuote("statmod"), " is required for nGQ > 60") } } ##' Calculate 2D Nodes and Weights of the Product Gauss Cubature ##' ##' @param xy list with elements \code{"x"} and \code{"y"} containing the ##' polygon vertices in \emph{anticlockwise} order (otherwise the result of the ##' cubature will have a negative sign) with first vertex not repeated at the ##' end (like \code{owin.object$bdry}). ##' @param nw_MN unnamed list of nodes and weights of one-dimensional Gauss ##' quadrature rules of degrees \eqn{N} and \eqn{M=N+1} (as returned by ##' \code{\link[statmod]{gauss.quad}}): \code{list(s_M, w_M, s_N, w_N)}. ##' @inheritParams polyCub.SV ##' @references ##' Sommariva, A. and Vianello, M. (2007): ##' Product Gauss cubature over polygons based on Green's integration formula. ##' \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. ##' @keywords internal ##' @useDynLib polyCub C_polygauss polygauss <- function (xy, nw_MN, alpha = NULL, rotation = FALSE, engine = "C") { ## POLYGON ROTATION xyrot <- if (identical(FALSE, rotation)) { if (is.null(alpha)) { # choose midpoint of x-range xrange <- range(xy[["x"]]) alpha <- (xrange[1L] + xrange[2L]) / 2 } angle <- 0 xy[c("x", "y")] } else { ## convert to coordinate matrix xy <- cbind(xy[["x"]], xy[["y"]], deparse.level=0) ## determine P and Q if (identical(TRUE, rotation)) { # automatic choice of rotation angle ## such that for a convex polygon all nodes fall inside the polygon QP <- vertexpairmaxdist(xy) Q <- QP[1L,,drop=TRUE] P <- QP[2L,,drop=TRUE] } else if (is.list(rotation)) { # predefined rotation P <- rotation$P Q <- rotation$Q stopifnot(is.vector(P, mode="numeric") && length(P) == 2L, is.vector(Q, mode="numeric") && length(Q) == 2L) stopifnot(any(P != Q)) rotation <- TRUE } else { stop("'rotation' must be logical or a list of points \"P\" and \"Q\"") } rotmat <- rotmatPQ(P,Q) angle <- attr(rotmat, "angle") if (is.null(alpha)) { Prot <- rotmat %*% P alpha <- Prot[1] } xyrot <- xy %*% t(rotmat) # = t(rotmat %*% t(xy)) ## convert back to list list(x = xyrot[,1L,drop=TRUE], y = xyrot[,2L,drop=TRUE]) } ## number of vertices L <- length(xyrot[[1L]]) ## COMPUTE 2D NODES AND WEIGHTS. if (engine == "R") { toIdx <- c(seq.int(2, L), 1L) nwlist <- mapply(.polygauss.side, xyrot[[1L]], xyrot[[2L]], xyrot[[1L]][toIdx], xyrot[[2L]][toIdx], MoreArgs = c(nw_MN, alpha), SIMPLIFY = FALSE, USE.NAMES = FALSE) nodes <- c(lapply(nwlist, "[[", 1L), lapply(nwlist, "[[", 2L), recursive=TRUE) dim(nodes) <- c(length(nodes)/2, 2L) weights <- unlist(lapply(nwlist, "[[", 3L), recursive=FALSE, use.names=FALSE) } else { # use C-implementation ## degrees of cubature and vector template for results M <- length(nw_MN[[1L]]) N <- length(nw_MN[[3L]]) zerovec <- double(L*M*N) ## rock'n'roll nwlist <- .C(C_polygauss, as.double(xyrot[[1L]]), as.double(xyrot[[2L]]), as.double(nw_MN[[1L]]), as.double(nw_MN[[2L]]), as.double(nw_MN[[3L]]), as.double(nw_MN[[4L]]), as.double(alpha), as.integer(L), as.integer(M), as.integer(N), x = zerovec, y = zerovec, w = zerovec)[c("x", "y", "w")] nodes <- cbind(nwlist[[1L]], nwlist[[2L]], deparse.level=0) weights <- nwlist[[3L]] ## remove unset nodes from edges on baseline or orthogonal to it ## (note that the R implementation does not return such redundant nodes) if (engine == "C+reduce" && any(unset <- weights == 0)) { nodes <- nodes[!unset,] weights <- weights[!unset] } } ## back-transform rotated nodes by t(t(rotmat) %*% t(nodes)) ## (inverse of rotation matrix is its transpose) list(nodes = if (rotation) nodes %*% rotmat else nodes, weights = weights, angle = angle, alpha = alpha) } ## The working horse .polygauss.side below is an R translation ## of the original MATLAB implementation by Sommariva and Vianello (2007). .polygauss.side <- function (x1, y1, x2, y2, s_loc, w_loc, s_N, w_N, alpha) { if ((x1 == alpha && x2 == alpha) || (y2 == y1)) ## side lies on base-line or is orthogonal to it -> skip return(NULL) if (x2 == x1) { # side is parallel to base-line => degree N s_loc <- s_N w_loc <- w_N } half_pt_x <- (x1+x2)/2 half_length_x <- (x2-x1)/2 half_pt_y <- (y1+y2)/2 half_length_y <- (y2-y1)/2 ## GAUSSIAN POINTS ON THE SIDE. x_gauss_side <- half_pt_x + half_length_x * s_loc y_gauss_side <- half_pt_y + half_length_y * s_loc scaling_fact_minus <- (x_gauss_side - alpha) / 2 ## construct nodes and weights: x and y coordinates ARE STORED IN MATRICES. ## A COUPLE WITH THE SAME INDEX IS A POINT, i.e. P_i=(x(k),y(k)). ## Return in an unnamed list of nodes_x, nodes_y, weights ## (there is no need for c(nodes_x) and c(weights)) list(alpha + tcrossprod(scaling_fact_minus, s_N + 1), # degree_loc x N rep.int(y_gauss_side, length(s_N)), # length: degree_loc*N tcrossprod(half_length_y*scaling_fact_minus*w_loc, w_N)) # degree_loc x N } ## NOTE: The above .polygauss.side() function is already efficient R code. ## Passing via C only at this deep level (see below) turned out to be ## slower than staying with R! However, stepping into C already for ## looping over the edges in polygauss() improves the speed. ## ## @useDynLib polyCub C_polygauss_side ## .polygauss.side <- function (x1, y1, x2, y2, s_M, w_M, s_N, w_N, alpha) ## { ## if ((x1 == alpha && x2 == alpha) || (y2 == y1)) ## ## side lies on base-line or is orthogonal to it -> skip ## return(NULL) ## ## parallel2baseline <- x2 == x1 # side is parallel to base-line => degree N ## M <- length(s_M) ## N <- length(s_N) ## loc <- if (parallel2baseline) N else M ## zerovec <- double(loc * N) ## .C(C_polygauss_side, ## as.double(x1), as.double(y1), as.double(x2), as.double(y2), ## as.double(if (parallel2baseline) s_N else s_M), ## as.double(if (parallel2baseline) w_N else w_M), ## as.double(s_N), as.double(w_N), as.double(alpha), ## as.integer(loc), as.integer(N), ## x = zerovec, y = zerovec, w = zerovec)[c("x", "y", "w")] ## } ##' @importFrom stats dist vertexpairmaxdist <- function (xy) { ## compute euclidean distance matrix distances <- dist(xy) size <- attr(distances, "Size") ## select two points with maximum distance maxdistidx <- which.max(distances) lowertri <- seq_along(distances) == maxdistidx mat <- matrix(FALSE, size, size) mat[lower.tri(mat)] <- lowertri QPidx <- which(mat, arr.ind=TRUE, useNames=FALSE)[1L,] xy[QPidx,] } rotmatPQ <- function (P, Q) { direction_axis <- (Q-P) / sqrt(sum((Q-P)^2)) ## determine rotation angle rot_angle_x <- acos(direction_axis[1L]) rot_angle_y <- acos(direction_axis[2L]) rot_angle <- if (rot_angle_y <= pi/2) { if (rot_angle_x <= pi/2) -rot_angle_y else rot_angle_y } else { if (rot_angle_x <= pi/2) pi-rot_angle_y else rot_angle_y } ## cat(sprintf(' [ANGLE CLOCKWISE (IN DEGREES)]: %5.5f\n', rot_angle*180/pi)) ## rotation matrix rot_matrix <- diag(cos(rot_angle), nrow=2L) rot_matrix[2:3] <- c(-1,1) * sin(rot_angle) # clockwise rotation structure(rot_matrix, angle=rot_angle) } polyCub/R/polyCub.iso.R0000644000176000001440000002344612422413675014470 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2013-2014 Sebastian Meyer ### Time-stamp: <[polyCub.iso.R] 2014-10-24 11:11 (CEST) by SM> ################################################################################ #' Cubature of Isotropic Functions over Polygonal Domains #' #' Conducts numerical integration of a two-dimensional isotropic function #' \eqn{f(x,y) = f_r(||(x,y)-\boldsymbol{\mu}||)}{f(x,y) = f_r(||(x,y)-\mu||)}, #' with \eqn{\mu} being the center of isotropy, over a polygonal domain. #' It internally solves a line integral along the polygon boundary using #' \code{\link{integrate}} where the integrand requires the antiderivative of #' \eqn{r f_r(r)}), which ideally is analytically available and supplied to the #' function as argument \code{intrfr}. #' The two-dimensional integration problem thereby reduces to an efficient #' adaptive quadrature in one dimension. #' See Meyer and Held (2014, Supplement B, Section 2.4) for mathematical #' details. #' #' @inheritParams plotpolyf #' @param intrfr analytical antiderivative of \eqn{r f_r(r)} from 0 to \code{R} #' (first argument, not necessarily named \code{"R"}, must be vectorized). #' If missing, \code{intrfr} is approximated numerically using #' \code{\link{integrate}} configured with \code{control}. #' @param ... further arguments for \code{f} or \code{intrfr}. #' @param center numeric vector of length 2, the center of isotropy. #' @param control list of arguments passed to \code{\link{integrate}}, the #' quadrature rule used for the line integral along the polygon boundary. #' @param check.intrfr logical (or numeric vector) indicating if #' (for which \code{r}'s) the supplied \code{intrfr} function should be #' checked against a numeric approximation. This check requires \code{f} #' to be specified. If \code{TRUE}, the set of test #' \code{r}'s defaults to a \code{\link{seq}} of length 20 from 1 to #' the maximum absolute x or y coordinate of any edge of the \code{polyregion}. #' @param plot logical indicating if an image of the function should be plotted #' together with the polygonal domain, i.e., #' \code{\link{plotpolyf}(polyregion, f, \dots)}. #' @return The approximate integral of the isotropic function #' \code{f} over \code{polyregion}.\cr #' If the \code{intrfr} function is provided (which is assumed to be exact), an #' upperbound for the absolute integration error is appended to the result as #' attribute \code{"abs.error"}. It equals the sum of the absolute errors #' reported by all \code{\link{integrate}} calls #' (there is one for each edge of \code{polyregion}). #' @author Sebastian Meyer #' #' The basic mathematical formulation of this efficient integration for radially #' symmetric functions was ascertained with great support by #' Emil Hedevang (2013), Dept. of Mathematics, Aarhus University, Denmark. #' @references #' Hedevang, E. (2013). Personal communication at the Summer School on Topics in #' Space-Time Modeling and Inference (May 2013, Aalborg, Denmark). #' #' Meyer, S. and Held, L. (2014). #' Power-law models for infectious disease spread. #' \emph{The Annals of Applied Statistics}, \bold{8} (3), 1612-1639.\cr #' DOI-Link: \url{http://dx.doi.org/10.1214/14-AOAS743}, #' \href{http://arxiv.org/abs/1308.5115}{arXiv:1308.5115} #' @keywords math spatial #' @family polyCub-methods #' @example inst/examples/polyCub.iso.R #' @importFrom stats integrate #' @export polyCub.iso <- function (polyregion, f, intrfr, ..., center, control = list(), check.intrfr = FALSE, plot = FALSE) { polys <- xylist(polyregion) # transform to something like "owin$bdry" # which means anticlockwise vertex order with # first vertex not repeated getError <- !missing(intrfr) # can't estimate error of double approximation ## check 'intrfr' function rs <- if (isTRUE(check.intrfr)) { seq(1, max(abs(unlist(lapply(polys, "[", c("x","y"))))), length.out=20L) } else if (identical(check.intrfr, FALSE)) { numeric(0L) } else { check.intrfr } intrfr <- checkintrfr(intrfr, f, ..., center=center, control=control, rs=rs) ## plot polygon and function image if (plot) plotpolyf(polys, f, ...) ## do the cubature over all polygons of the 'polys' list .polyCub.iso(polys, intrfr, ..., center=center, control=control, .witherror=getError) } ##' Check the Integral of \eqn{r f_r(r)} ##' ##' This function is auxiliary to \code{\link{polyCub.iso}}. ##' The (analytical) integral of \eqn{r f_r(r)} from 0 to \eqn{R} is checked ##' against a numeric approximation using \code{\link{integrate}} for various ##' values of the upper bound \eqn{R}. A warning is issued if inconsistencies ##' are found. ##' ##' @inheritParams polyCub.iso ##' @param rs numeric vector of upper bounds for which to check the validity of ##' \code{intrfr}. If it has length 0, no checks are performed. ##' @param tolerance of \code{\link{all.equal.numeric}} when comparing ##' \code{intrfr} results with numerical integration. Defaults to the ##' relative tolerance used for \code{integrate}. ##' @return The \code{intrfr} function. If it was not supplied, its quadrature ##' version using \code{integrate} is returned. ##' @importFrom stats integrate ##' @export checkintrfr <- function (intrfr, f, ..., center, control = list(), rs = numeric(0L), tolerance = control$rel.tol) { doCheck <- length(rs) > 0L if (!missing(f)) { f <- match.fun(f) rfr <- function (r, ...) r * f(cbind(center[1]+r, center[2], deparse.level=0), ...) quadrfr1 <- function (r, ...) integrate(rfr, 0, r, ...)$value if (length(control)) body(quadrfr1)[[2]] <- as.call(c(as.list(body(quadrfr1)[[2]]), control)) quadrfr <- function (r, ...) sapply(r, quadrfr1, ..., USE.NAMES=FALSE) if (missing(intrfr)) { return(quadrfr) } else if (doCheck) { cat("Checking 'intrfr' against a numeric approximation ... ") stopifnot(is.vector(rs, mode="numeric")) if (is.null(tolerance)) tolerance <- eval(formals(integrate)$rel.tol) ana <- intrfr(rs, ...) num <- quadrfr(rs, ...) if (!isTRUE(comp <- all.equal(num, ana, tolerance=tolerance))) { cat("\n->", comp, "\n") warning("'intrfr' might be incorrect: ", comp) } else cat("OK\n") } } else if (doCheck) { stop("numerical verification of 'intrfr' requires 'f'") } match.fun(intrfr) } ##' \code{.polyCub.iso} is a \dQuote{bare-bone} version of \code{polyCub.iso}. ##' @rdname polyCub.iso ##' @param polys something like \code{owin$bdry}, but see \code{\link{xylist}}. ##' @param .witherror logical indicating if an upperbound for the absolute ##' integration error should be attached as an attribute to the result? ##' @export .polyCub.iso <- function (polys, intrfr, ..., center, control = list(), .witherror = FALSE) { ints <- lapply(polys, polyCub1.iso, intrfr, ..., center=center, control=control, .witherror=.witherror) if (.witherror) { structure(sum(sapply(ints, "[", 1, simplify=TRUE, USE.NAMES=FALSE)), abs.error=sum(sapply(ints, "[", 2, simplify=TRUE, USE.NAMES=FALSE))) } else { sum(unlist(ints, recursive=FALSE, use.names=FALSE)) } } ## cubature method for a single polygon polyCub1.iso <- function (poly, intrfr, ..., center, control = list(), .witherror = TRUE) { xy <- cbind(poly[["x"]], poly[["y"]], deparse.level=0) nedges <- nrow(xy) intedges <- erredges <- numeric(nedges) for (i in seq_len(nedges)) { v0 <- xy[i, ] - center v1 <- xy[if (i==nedges) 1L else i+1L, ] - center int <- lineInt(v0, v1, intrfr, ..., control=control) intedges[i] <- int$value erredges[i] <- int$abs.error } int <- sum(intedges) ## if (!is.null(poly$hole) && !isTRUE(all.equal(0, int))) { ## if ((1 - 2 * as.numeric(poly$hole)) * sign(int) == -1) ## warning("wrong sign if positive integral") ## } c(int, if (.witherror) sum(erredges)) } ## line integral for one edge ##' @importFrom stats integrate lineInt <- function (v0, v1, intrfr, ..., control = list()) { d <- v1 - v0 num <- v1[2]*v0[1] - v1[1]*v0[2] # = d[2]*p[,1] - d[1]*p[,2] # for any point p on the edge integrand <- function (t) { ## get the points on the edge corresponding to t p <- cbind(v0[1] + t*d[1], v0[2] + t*d[2], deparse.level=0) norm2 <- .rowSums(p^2, length(t), 2) ints <- intrfr(sqrt(norm2), ...) ##ints[is.infinite(ints)] <- 1e300 num * ints / norm2 } if (length(control)) { # use slower do.call()-construct do.call("integrate", c(list(integrand, 0, 1), control)) } else { integrate(integrand, 0, 1) } } ## equally fast method _only_ for convex polygonal domains including the origin ## (formula obtained via polar coordinate representation) lineInt2 <- function (v0, v1, intrfr, ..., control = list()) { d <- v1 - v0 ld <- vecnorm(d) l0 <- vecnorm(v0) l1 <- vecnorm(v1) dp <- dotprod(v0,v1) theta <- acos((l0 - dp/l0) / ld) num <- sin(theta) * l0 phispan <- acos(dp / l0 / l1) integrand <- function (phi, ...) { r <- num / sin(theta+phi) intrfr(r, ...) } do.call("integrate", c(list(integrand, 0, phispan, ...), control)) } polyCub/R/polyCub.R0000644000176000001440000000444712165773342013703 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2013 Sebastian Meyer ### Time-stamp: <[polyCub.R] by SM Sam 06/07/2013 12:52 (CEST)> ################################################################################ #' Wrapper Function for the Various Cubature Methods #' #' Instead of calling one of the specific cubature methods of this package, the #' wrapper function \code{polyCub} may be used together with the \code{method} #' argument. #' #' @param polyregion a polygonal integration domain. #' The supported classes depend on the specific method, however, the #' \code{"\link[spatstat]{owin}"} class from package \pkg{spatstat} works for #' all methods, as well should a \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} #' polygon (but see the comments in \code{help("\link{coerce-methods}")}). #' @param f two-dimensional function to be integrated. #' As its first argument the function must take a coordinate matrix, i.e. a #' numeric matrix with two columns. For the \code{"exact.Gauss"} \code{method}, #' \code{f} is ignored since it is specific to the bivariate normal density. #' @param method choose one of the implemented cubature methods (partial #' argument matching is applied), see \code{help("\link{polyCub-package}")} #' for an overview. Defaults to using the product Gauss cubature #' implemented in \code{\link{polyCub.SV}}. #' @param ... arguments of \code{f} or of the specific \code{method}. #' @param plot logical indicating if an illustrative plot of the numerical #' integration should be produced. #' @return The approximated integral of \code{f} over \code{polyregion}. #' @example inst/examples/polyCub.R #' @keywords math spatial #' @family polyCub-methods #' @export polyCub <- function (polyregion, f, method = c("SV", "midpoint", "iso", "exact.Gauss"), ..., plot = FALSE) { method <- match.arg(method) cl <- match.call() cl$method <- NULL cl[[1]] <- as.name(paste("polyCub", method, sep=".")) if (method == "exact.Gauss") cl$f <- NULL int <- eval(cl, parent.frame()) int #structure(int, method = method) } polyCub/R/sysdata.rda0000644000176000001440000004464412375634461014307 0ustar ripleyusers7zXZi"6!X|Ih])TW"nRʟ)'dz$&}T1}} IL9d]hϐf Qcv\ DÿNրGsFcw}8=ɥ""(U= b4 Yq:>qx6J6LUB4x}0&[g"QCBb9,xgeދ|`$ٔ'Nz#3< @?4򬐱kw,askfG 8ym['ZlDrKG3C,ACI[ :Qms]볾+) 1ER˹FbK%uaR4f!5P)~+LbBF{Oq@mHMN+`]rWI5O.Sޟ\BlO!ɫB|UK-sk<`p[_FЁ'v`¬#Ȯd3D}hm _04zYeWgU -}_ϬH>4dbn* &!d0L!d҆;b.jH)\9м AJa_F>={i*[B$85͋͞;fy+ !+ϷW6g_ \Mj'0c ې2(̮jE'd,m ʓ(emgW| ߒA6VʰB`M91 iOY -H/Ş3D ,6PKZrN02p jӢOo C])˧.-h[c6G_ڢZdvy L˜ه)"$mluu誣H%6BC7IxJb4(K\`343u*ҡ>Lׇ.Inm0j )/\J)r6wjӳQW1M>}(BYż{s)q My pUAvsUj0h1qd),C\-v`7[1}%l7݂(&{d a~t0Ŗyfk_lJ:0JM^g X+.2{ZFG_e5x+}OY5kА-JFo⑐5_Q :!I^oO}e%oG8xO*ݿ <^Lx8o}~;u/T%6AejBB R63*7(QL#iZLԤ?GokLhۻ.0 =--[Aaϗ/x\㇑&$q+p!6e=j;+^Nq=v%"tJ$2/:Ȳ3EBJ@rŘHKEGkڂ2t=,Nes!2MXO9ԲoDaU~7qÔ9yn/ot' 7oYz\2z䘯 P+r f0pQ-hG̨Lܗo.w'/mGИ Ah9fݳ(+xaF-[G5O1\6ǜDD\dd۷bqK1GqpВjՂb;ǑlnlP!\6Gsi AQcxl 4ugB`$ L 5  p3K8c,4H35ܰJt.V Cꈥx-juv.NcJW2 /}ݽxW)qS<f;8ؿ,U2Pt/F}'懂 ?GC,馸tU|PZ(36{s@e> _٭5-*WX:l|P…df9րu Hs s>kǴ-ZZ#vnz\Ɂ3'̐`Az]rw? $Y2j^ܩQ@xr68R=r!r1YmWS<%c Hjɺ{ilL6~ҝ/~eڕrhBA vJV/q5cr`*Z庅PJ8Zڲ찭ȃD7˔?OΟ7a1clf咦n*_R U\KS്iNB:fO{!B3 592#9-Ȅ=jC7m^R3ސ%u [U/|ih R~xK@|[!Xd~:"OEmpE߃Ԋs2ӺK6OŮ )..k{WCbG] ȸ>q4Psn&vE¦<|E΄1|ibBR;U}h.vY^ pmZ_0nAYxlBW6*ZP ]gV>ɉf_ l/hOy˔d[СYLE'a]$,o[ưuuVHF(XfH'q~pf>9k7ޔ3`A(hzs*n԰-jyxěѥ$ *l'EXTmE%۟cc[0J}= 4AT+:oju-b[e>QaD0*H P󆑕3w"C 57;Fd|k4U/-I8aEw]EI>0Ӳf,Kw:}!!|d9=ч1 u*1YWȘYrT##?>FVT1[_Rz2a!W2NyH; bb~ӄdʲ 6B}N4:/ 7zEW3Wn9ee޲ ն*9:ڽcoL64/+Fpqyr :9`͚ŭU~d;%6] 2kMexHp'ˁ0rW6dEk#^a+) cё9J-I`4[Lː]t7ķ2 0#k1?L}l*Q2[-ʹ,;#RX1$dᖩC cա:NعX (錼;G15 `%XOJV%?Ek:uy#Ǝ]}-`)w\MgEdX+ndY ^L)HQk {+—Qꦋ,(ض4h'|ÞD _`mcPφζ6UӳƼ=Ԯm";N`CAh`(Jq-I8ξq4( `BH/h[r#hvp7?%^q|"JU6j6[OG=*&'p8a. ; 6s_EѮD?Z=m2Ղ:8fgɌx‡]S&WCZq"Wɖ5_||Ѝ.ٌ%5923GCQD-K IJ #2]dM7[*A?&en6qY}dBPiz48V|)k`OFoTW)h{Fn$ӂ';Daڂ1K{إ> 1QwrH" !gb=j-"xF=6%Qgjd'wf_1@bZlm*^a#Hf"6ǭ+ǹhc}| x2#r~V,^M@tlyY<[<(gV󋇅@ %>l:+8iE&6{v()#Q(Yy],>kv.A2M'JTZ6RfaN%8i%Lez81\*Zyx[N; + GEft_9M"^[R`J_1A(S돭 }Of*wH_(`bcFUNMѝUAeگf Aў|m_1sڠ~  [diwbZ˚wEe9Hb1Y&ɂ 7x"\D9ΞKztE쌛xq>ˎ&R^D$lfO~zs9P[ը2'NRx O=F (hu |'{ڗߛ6P2Dhb+[ _W}rtyl3&38~;N yQփ-Fc#J5e bdP/gǂr@ϟrʛf0CU[ug SLVNepZ|JT.&Qmu \'tZ-cC[FU5b 7f"wJ|ϊWJXu8SItS˼A~1crgJ'̱Q@՗0Kj{dG׏YT0>o⋢jL!d*\cM8na <^ )بh&߷)%QVu$%c42MCBQ|T<,eSu|K~;5kDC-T9G=$?TۚHQS%$ wLq*Bp'W.>34~#9qĹlZ XSjؖ-.VP33 QQ2+QC,ےOG$)Y&ފ#bnPšmC <%q Bc.SҖ[QF-k;~O{8N9&Yǽ5SqS"-[gQyK )s2VYVv=KNΡ{Ju y9D,[׺YYxZؓVȫ.õN{822Xye z4}p7QCzU~&lNuǓa@4zPԊMUvWij-؆O_2+whF)NM?7쪖o p;{xi<?cCN,ƕvMP c!Mxp*^D_^*\0v%S5N'{G|8sգZ w3'.*kx[0읏 Ca(]Mڢ@՗>)*Dez礩izh- xP*+qʂ3C-fKN*DnzX{¥Y3b{?PLcps!<+2j|}`mZ=Ѫe#e[wdJq# 7ƴFLL4ՙ賗hrHY$ )IRl?lOWFwBc+L1(t9-eD:6J*[̏ /o{!n;/vEXc8XETU#ayC DxF*,R꒸3ؿM1eLNrjYR@mi쭢SMMfנ/h`ҹc>i)~ur=#b_b .q_gK ǟ ؿ!pHC#*n gli-D晱:~xywjјq{ BTzdםv3WTgNzn|ATW =K_WUE;õE5V 3˓c $pmNb  ؇ǘ#(:tyyb! zgILlC1ARG<=6a GkD & aA"Sw^)з:YsC.۠:!LqOi1 fG۟E(7'k^Y`X=D-kHXl.㪙¤?zY~-<ĵ+zL+.iHFO6˦D!$ e/ +s~4#AIZX8[1?Ł>n#>8JE}cڳ%1vfTlC6nʽkmӕD$h1˚9MXy;1 tnsIa lWџW \L Xi.By sHu]M|sf٠}Q\[ ] qosl?h!)+#ͬ|IտۀRӯl􋗥58I&IMO5=~DOl2T|1QRjo/.}1 d~c銧۫Oa{jbBMi4K<$^.qp@Di:"gt*:'TċּeufšFEb׳eteV%ML(̸kY^oƒyOG*$wkWe3t*mV!XL%fzn3s,F3JxAV0N!{{§&5"XkiUٜ (䄔Cp@sukFݎpŢd( sENffI3/݅WG{8} jtzlGM]`! T/毌@(l >d`[q&YW6/p9j)naQ!| jwн\,4 j=G;s2ljRi_y@<,j(`Ba:`<,vWpI_pP5aq7Z<2=IҨE\e-CLzh„/9Rz{ U: cnZ0!H mW>#Q;_܍'Afi^N>JޡXȊ<VkAg$"Fs@]V?-AdzFKh||*, O0.T _n`mH<#?ɀSsTg?NSg/ EÿXLE{v,(}gp=QR& kMW#y\ӊebq&$Nx] ɼBqt xd36`Pl@w~372R] \too׏ $^Ar:HK ]s؀DU)07+=͡]=դz̩6h+8zj;C@4N z`4( ):PW)ad?aYoyEb7XIeF"_9in1\PWD,c`SpqW׉/VS(ŭI8KՀѕ.Kfm_oطrٗ#7 ~#'{ !^> tbi;0!1~/ 6Z(CDZz[2 bRdOI WOI*07M8Fas[ʘ6"&E)F(Ĉ-t(bORڮˢ< ˱GUx!m}Ztv|%RXc;ȢA\!ڌ_Z`p]͇ѠFKzNy}vMs{:1<~UcT9Woo5geLҮL@cTAvAN,st İ vM,ʐLڹń)ӎ[kDh0o: wdrf3qhmpMxDm%Wɡ(e>,!#bTxVٲ6F[vo|`3Gf' 矵-^LsYvIcNH 2рΏW{%f5U=30O?Rue<''Z[07p?%wrO=!wLAumҕ&̓^%٨{߷OjKPoS[.mз~wcLg|5S\Dܑ$b$v5_;[EpfEgNz0>+u`lj?:J*D/ky?+}yV*<5V_ y:-q|SL_*6MȱKEKXF҆SH"( Q= E*Q'?}m&mAD}:sQ_//2j*pl޼d(}prL5O,8wQbmѪ$'#$_í"kM[9<-xm=3  &`V2q0!yY9gVlc4}bi!v>W@zvJPqjrNRNҞ`_*';n Ny+AONW.dM>֚\F2J}ItVDwDN4zTޢHd8 60re<Ta"mpYȀ#FVo:a ]k-A?úٷ^}.8B&cV" 1Ujb>^WR jiܻs)cN\}dF9$qĞmSffuY\{r_F%vIeD]ϨN7!?Vvf.a""Fzi60#; }_f % *rM#KZ[?cOgsLbmÈnpFӲY5(R$=% 4$qWof [?A`*y+uRR[N?'R}SgDZ.u%ꘌT˕c( cPKdŤU P.<m~aٔW 8a8dVU3!6b 'ܔ=JX4NjbGBl72E/*ƁǏn K 1Yy\GTYpi. Cff3DJ!:%f(nޫzjK:K0@3I2K?IJm[ܰ y@R}w@}~rK>,ƨ =5_UWW-SGMՆa=LULp4vo Qrgp7Ў̡p(o2W #]gpm)e!ѹم4>O uhm{7C {@D+>è\}'I:VSoD"0a @O_|cBow?JɓOJej`ëG6ԾuޏXc%^I`^K mM^<fHjAc.oӶM;k(tq 8Lb|C9اq*s6 9/P@(3"F)$_} ~s "p!d2(1.uYSIQX7pw3KB G.sDs) d7tGn?-WeOPi8Yzǚ8^ hTk_">M,v{=ýɻq/*ؖ[QfXS6/; &kمn==p [9-l d5V5sڢX+YƤx *"(˦Һ}3p+N36H\޿&S4,>xݐԪqN8t t y~MҎ8rXyѵ7dq1K=%H_ISt]@h"uƯP6U-F?sI)r-.xT,+3WH'Ql̬0sUNZ3h ܈-MBՠ{ 7^ѹS=u8fo"? D$zVTl9c˞U'F}AE 1ZbV()-Q36Mp!֘ A9kuۈtg]S<%e"Rհu[kri^BOP!U)y|KbLn:qNG2.P-;G>Yl%腰=O/sjwʿ+OQhKfCۄ]@l_VI! We3 qDT$}Dlq"J }=O-kEBzvl^MiDHӧ{I`K@qq''%FiS3M&S0F?2eEkͤ s,;!,_t/]R=<Al]=  Hv$ݼadn_^Yuu;6_S0[EI!**q\#a}wGG͍S,"J!+0Hh(w #U 3)|cjJW[IrŻ:ҝ|@zC~a>A?[蹺a}?,\hI󺡹8U&6C5K=S> V}-_,!~=1XT S8e|h,No}Nۿ9E&^HLm*%^܈v/Nto1ӑJE%kkݚX/ l[_{qkR|0ۀ 00{k4HV_z{F_\]*W-> &`Mt oUHsԂ+YE|kwQxa =+b4p &F2lj9!h|!-`3tWw-jj,EﮓSS[ۈ=:+LsՁ [+ -kIi겂f%tIjY#E*u}ϒ}c Q5d .KCeCI0>+ KU*xEʊ17 NMK/O_x̲)PzI| S %\l[2|I 3oh;,j1ѨLx7pvpyFsE H*M$>'e:w fT!UrL!&lDF% aάm9w"5s>|펻86_FyV8A w9_a =IzNLc\Gg3g8v$#'Hf@8EG1MJv"u*\CG"7"[C6Mdy.bQV,xWlQvQmv֓|~O곀NoC#nN>iyI4|B$)=' ߤ$\0 ynmo SO8bKfRo5UVclW;e1{,dٷ r+!"m/Xq$;Idn NcY.9R `MWև;9"yAz SAF(rH翿^~DX0.~Nqs'SȀ0'Hu]'D &$nJZhy"N, z(h$W[Hj1MTr "ZޅQGtM`663S/_XJwz"Elgl~YuEc@: cN7}!~ kn{n@̘/lX>NP%=\s{ZYzB9A/"pV^EK8la2 "2yn~buts6/>OU^Ja#)&-肈,<ȸ $?N5M0^9w;б# \PVN |J!6FU  i59Rb@2 P\a$~lr D R-@ݘL ۴Hn m\dٲ#(3OEd{`J!a<./d/&kG!tpV#@zJJL+\@ZF>u?{ jRPj^.;7C:D %㶫IP=vؔIB/gGA :xa_O>Ï]>V|7Iv0ܷ[(c2NohCdl,4ҒP).+mD~.0zk2Mո o+)!p]Ct] ;),KԅdyㆁdIG۔52߳J@HD$DO%̊ Q Eݤ`j%A'{Px'PچpBj/zʱABfC[% Juǿt=ih=v>ĜYj 1PT*kb_z8\WW9MCjV}.}JO7E5)jMxH GvDOz:W A#W7B3b7"MTG%n,c(p1 Fqkix?A9]@3-/>0 YZpolyCub/R/polyCub.midpoint.R0000644000176000001440000000657112411522007015505 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2014 Sebastian Meyer ### Time-stamp: <[polyCub.midpoint.R] 2014-09-27 13:48 (CEST) by SM> ################################################################################ #' Two-Dimensional Midpoint Rule #' #' The surface is converted to a binary pixel image #' using the \code{\link[spatstat]{as.im.function}} method from package #' \pkg{spatstat} (Baddeley and Turner, 2005). #' The integral under the surface is then approximated as the #' sum over (pixel area * f(pixel midpoint)). #' #' @inheritParams plotpolyf #' @param polyregion a polygonal integration domain. #' It can be any object coercible to the \pkg{spatstat} class #' \code{"\link[spatstat]{owin}"} (via \code{\link[spatstat]{as.owin}}). #' @param eps width and height of the pixels (squares), #' see \code{\link[spatstat]{as.mask}}. #' @param dimyx number of subdivisions in each dimension, #' see \code{\link[spatstat]{as.mask}}. #' @param plot logical indicating if an illustrative plot of the numerical #' integration should be produced. #' @return The approximated value of the integral of \code{f} over #' \code{polyregion}. #' @references #' Baddeley, A. and Turner, R. (2005). #' \pkg{spatstat}: an \R package for analyzing spatial point patterns. #' \emph{Journal of Statistical Software}, \bold{12} (6), 1-42. #' @keywords math spatial #' @family polyCub-methods #' @import sp #' @importFrom spatstat as.im.function plot.im #' @importFrom grDevices gray #' @examples # see example(polyCub) #' @export ## NOTE: we don't import graphics::plot since it is already imported via sp polyCub.midpoint <- function (polyregion, f, ..., eps = NULL, dimyx = NULL, plot = FALSE) { ## as.im needs seperate x and y arguments fxy <- function (x, y, ...) f(cbind(x,y), ...) ## calculate pixel values of fxy IM <- tryCatch( as.im.function(X=fxy, W=polyregion, ..., eps=eps, dimyx=dimyx), error = function (e) { ## if eps was to small such that the dimensions of the image would ## be too big then the operation matrix(TRUE, nr, nc) throws an ## error. (try e.g. devnull <- matrix(TRUE, 1e6,1e6)) ## unfortunately, it is not clear what we should do in this ## case... => stop stop("inapplicable choice of bandwidth (eps=", format(eps), ") in midpoint rule:\n", e) }) ### ILLUSTRATION ### if (plot) { plot.im(IM, axes=TRUE, col=gray(31:4/35), main="") ## add evaluation points (unsure about spatstat implementation of class "im") ## both of the following commands worked with different versions of spatstat #with(IM, points(expand.grid(xcol, yrow), col=!is.na(v), cex=0.5)) #with(IM, points(expand.grid(y=yrow, x=xcol)[2:1], col=!is.na(v), cex=0.5)) plot(polyregion, add=TRUE, poly.args=list(lwd=2), lwd=2) ##<- two 'lwd'-specifications such that it works with owin and gpc.poly } #################### ## return the approximated integral pixelarea <- IM$xstep * IM$ystep int <- pixelarea * sum(IM$v, na.rm = TRUE) int } polyCub/R/xylist.R0000644000176000001440000001114312422131430013567 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2012-2014 Sebastian Meyer ### Time-stamp: <[xylist.R] 2014-10-23 09:49 (CEST) by SM> ### ### Convert various polygon classes to a simple "xylist" ################################################################################ ##' Convert Various Polygon Classes to a Simple List of Vertices ##' ##' Different packages concerned with spatial data use different polygon ##' specifications, which sometimes becomes very confusing (see Details below). ##' To be compatible with the various polygon classes, package \pkg{polyCub} ##' uses an S3 class \code{"xylist"}, which represents ##' polygons by their core feature only, a list of lists of vertex coordinates ##' (see the "Value" section below). ##' The generic function \code{xylist} can deal with the ##' following polygon classes: ##' \itemize{ ##' \item{\code{"\link[spatstat:owin.object]{owin}"} from package \pkg{spatstat}} ##' \item{\code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from package ##' \pkg{rgeos} (or \pkg{gpclib})} ##' \item{\code{"\link[sp:Polygons-class]{Polygons}"} from package \pkg{sp} ##' (as well as \code{"\link[sp:Polygon-class]{Polygon}"} and ##' \code{"\link[sp:SpatialPolygons-class]{SpatialPolygons}"})} ##' } ##' The (somehow useless) default \code{xylist}-method ##' does not perform any transformation but only ensures that the polygons are ##' not closed (first vertex not repeated). ##' ##' Different packages concerned with spatial data use different polygon ##' specifications with respect to: ##' \itemize{ ##' \item{do we repeat the first vertex?} ##' \item{which direction represents holes?} ##' } ##' Package overview: ##' \describe{ ##' \item{\pkg{sp}:}{\emph{Repeat} first vertex at the end (closed), ##' anticlockwise = hole, clockwise = normal boundary} ##' \item{\pkg{spatstat}:}{do \emph{not repeat} first vertex, ##' anticlockwise = normal boundary, clockwise = hole. This convention is also ##' used in \code{xylist}.} ##' \item{\pkg{gpclib}:}{Unfortunately, there seems to be no convention ##' for the specification of polygons of class \code{"gpc.poly"}.} ##' } ##' ##' @param object an object of one of the supported spatial classes. ##' @param ... (unused) argument of the generic. ##' @return Applying \code{xylist} to a polygon object, one gets a simple list, ##' where each component (polygon) is a list of \code{"x"} and \code{"y"} ##' coordinates. These represent vertex coordinates following \pkg{spatstat}'s ##' \code{"owin"} convention (anticlockwise order without repeating any vertex). ##' The opposite vertex order can be retained for the \pkg{sp}-classes ##' by the non-default use with \code{reverse=FALSE}. ##' @author Sebastian Meyer ##' @name xylist ##' @keywords spatial methods ##' @export xylist <- function (object, ...) UseMethod("xylist") ##' @rdname xylist ##' @importFrom spatstat as.polygonal ##' @export xylist.owin <- function (object, ...) { as.polygonal(object)$bdry } ##' @rdname xylist ##' @export xylist.gpc.poly <- function (object, ...) { xylist.owin(gpc2owin(object, check = FALSE)) } ##' @rdname xylist ##' @inheritParams xylist.Polygons ##' @export xylist.SpatialPolygons <- function (object, reverse = TRUE, ...) { unlist(lapply(object@polygons, xylist.Polygons, reverse=reverse, ...), recursive=FALSE, use.names=FALSE) } ##' @rdname xylist ##' @param reverse logical (\code{TRUE}) indicating if the vertex order of the ##' \pkg{sp} classes should be reversed to get the \code{xylist}/\code{owin} ##' convention. ##' @import sp ##' @export xylist.Polygons <- function (object, reverse = TRUE, ...) { lapply(object@Polygons, function (sr) { coords <- coordinates(sr) n <- nrow(coords) - 1L # number of vertices idxs <- if (reverse) seq.int(n,1) else seq_len(n) list(x = coords[idxs,1L], y = coords[idxs,2L]) #area = sr@area, hole = sr@hole }) } ##' @rdname xylist ##' @import methods ##' @export xylist.Polygon <- function (object, reverse = TRUE, ...) xylist.Polygons(as(object,"Polygons"), reverse=reverse, ...) ##' @rdname xylist ##' @importFrom grDevices xy.coords ##' @export xylist.default <- function (object, ...) { lapply(object, function (xy) { poly <- xy.coords(xy)[c("x","y")] if (isClosed(poly)) { sel <- seq_len(length(poly$x) - 1L) poly$x <- poly$x[sel] poly$y <- poly$y[sel] } poly }) } polyCub/R/polyCub.exact.Gauss.R0000644000176000001440000001664612332114707016061 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2014 Sebastian Meyer ### Time-stamp: <[polyCub.exact.Gauss.R] by SM Die 06/05/2014 10:13 (CEST)> ################################################################################ #' Quasi-Exact Cubature of the Bivariate Normal Density #' #' Integration is based on triangulation of the polygonal domain and formulae #' from the #' Abramowitz and Stegun (1972) handbook (Section 26.9, Example 9, pp. 956f.). #' This method is quite cumbersome because the A&S formula is only for triangles #' where one vertex is the origin (0,0). For each triangle of the #' \code{\link[gpclib]{tristrip}} we have to check in which of the 6 outer #' regions of the triangle the origin (0,0) lies and adapt the signs in the #' formula appropriately. (AOB+BOC-AOC) or (AOB-AOC-BOC) or (AOB+AOC-BOC) or #' (AOC+BOC-AOB) or \ldots. However, the most time consuming step is the #' evaluation of \code{\link[mvtnorm]{pmvnorm}}. #' #' @note The package \pkg{gpclib} (which is required to produce the #' \code{tristrip}, since this is not yet implemented in \pkg{rgeos}) #' has a restricted license (commercial use prohibited). #' It has to be accepted explicitly via #' \code{\link{gpclibPermit}()} prior to using \code{polyCub.exact.Gauss}. #' #' @param polyregion a \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} polygon or #' something that can be coerced to this class, e.g., an \code{"owin"} polygon #' (converted via \code{\link{owin2gpc}} and -- given \pkg{rgeos} is available #' -- \code{"SpatialPolygons"} also work. #' @param mean,Sigma mean and covariance matrix of the bivariate normal density #' to be integrated. #' @param plot logical indicating if an illustrative plot of the numerical #' integration should be produced. Note that the \code{polyregion} will be #' shifted and scaled. #' @return The integral of the bivariate normal density over \code{polyregion}. #' Two attributes are appended to the integral value: #' \item{nEval}{ #' number of triangles over which the standard bivariate normal density had to #' be integrated, i.e. number of calls to \code{\link[mvtnorm]{pmvnorm}} and #' \code{\link[stats]{pnorm}}, the former of which being the most time-consuming #' operation. #' } #' \item{error}{ #' Approximate absolute integration error steming from the error introduced by #' the \code{nEval} \code{\link[mvtnorm]{pmvnorm}} evaluations. #' For this reason, the cubature method is in fact only #' quasi-exact (as is the \code{pmvnorm} function). #' } #' @references #' Abramowitz, M. and Stegun, I. A. (1972). #' Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical #' Tables. New York: Dover Publications. #' @keywords math spatial #' @seealso \code{\link{circleCub.Gauss}} for quasi-exact cubature of the #' isotropic Gaussian density over a circular domain. #' @family polyCub-methods #' @examples # see example(polyCub) #' @import methods #' @import sp #' @importFrom stats cov2cor #' @importFrom spatstat is.polygonal #' @export ## NOTE: we don't import graphics::plot since it is already imported via sp polyCub.exact.Gauss <- function (polyregion, mean = c(0,0), Sigma = diag(2), plot = FALSE) { gpclibCheck(fatal=TRUE) if (is.polygonal(polyregion)) { polyregion <- owin2gpc(polyregion) } else if (!inherits(polyregion, "gpc.poly")) { loadNamespace("rgeos") polyregion <- as(polyregion, "gpc.poly") } ## coordinate transformation so that the standard bivariat normal density ## can be used in integrations (cf. formula 26.3.22) rho <- cov2cor(Sigma)[1,2] sdx <- sqrt(Sigma[1,1]) sdy <- sqrt(Sigma[2,2]) polyregion@pts <- lapply(polyregion@pts, function (poly) { list(x = ((poly$x-mean[1])/sdx + (poly$y-mean[2])/sdy) / sqrt(2+2*rho), y = ((poly$y-mean[2])/sdy - (poly$x-mean[1])/sdx) / sqrt(2-2*rho), hole = poly$hole) }) ## triangulation: tristrip() returns a list where each element is a ## coordinate matrix of vertices of triangles triangleSets <- gpclib::tristrip(polyregion) ### ILLUSTRATION ### if (plot) { plot(polyregion, poly.args=list(lwd=2), ann=FALSE) lapply(triangleSets, lines, lty=2) } #################### integrals <- sapply(triangleSets, function (triangles) { int <- 0 error <- 0 nTriangles <- nrow(triangles) - 2 for (i in seq_len(nTriangles)) { res <- .intTriangleAS(triangles[i+(0:2),]) err <- attr(res, "error") int <- int + res if (length(err) == 1L) error <- error + err ##<- sometimes err==numeric(0) (probably meaning err=0) } c(int, nTriangles, error) }) int <- sum(integrals[1,]) ## number of .V() evaluations ## (if 'h' in .intTriangleAS0 was always different from 0) attr(int, "nEval") <- 6 * sum(integrals[2,]) ## approximate absolute integration error attr(int, "error") <- sum(integrals[3,]) return(int) } ########################### ### Auxiliary Functions ### ########################### ## calculates the integral of the standard bivariat normal over a triangle ABC .intTriangleAS <- function (xy) { A <- xy[1,] B <- xy[2,] C <- xy[3,] intAOB <- .intTriangleAS0(A, B) intBOC <- .intTriangleAS0(B, C) intAOC <- .intTriangleAS0(A, C) # determine signs of integrals signAOB <- -1 + 2*.pointsOnSameSide(A,B,C) signBOC <- -1 + 2*.pointsOnSameSide(B,C,A) signAOC <- -1 + 2*.pointsOnSameSide(A,C,B) int <- signAOB*intAOB + signBOC*intBOC + signAOC*intAOC attr(int, "error") <- attr(intAOB, "error") + attr(intBOC, "error") + attr(intAOC, "error") return(int) } ## calculates the integral of the standard bivariat normal over a triangle A0B .intTriangleAS0 <- function (A, B) { d <- sqrt(sum((B-A)^2)) h <- abs(B[2]*A[1] - A[2]*B[1]) / d if (h == 0) return(0) k1 <- abs(A[1]*(B[1]-A[1]) + A[2]*(B[2]-A[2])) / d k2 <- abs(B[1]*(B[1]-A[1]) + B[2]*(B[2]-A[2])) / d V2 <- .V(h, k2) V1 <- .V(h, k1) res <- if (isTRUE(all.equal(k1+k2, d))) V2 + V1 else if (isTRUE(all.equal(abs(k2-k1), d))) abs(V2 - V1) else stop("something went wrong...") attr(res, "error") <- attr(V1, "error") + attr(V2, "error") return(res) } ## checks if point1 and point2 lie on the same side of a line through ## linepoint1 and linepoint2 .pointsOnSameSide <- function (linepoint1, linepoint2, point1, point2 = c(0,0)) { n <- c(-1,1) * rev(linepoint2-linepoint1) # normal vector S <- dotprod(point1-linepoint1,n) * dotprod(point2-linepoint1,n) return(S > 0) } ## calculates the integral of the standard bivariat normal ## over a triangle bounded by y=0, y=ax, x=h (cf. formula 26.3.23) ##' @importFrom stats pnorm .V <- function(h,k) { a <- k/h rho <- -a/sqrt(1+a^2) # V = 0.25 + L(h,0,rho) - L(0,0,rho) - Q(h) / 2 # L(0,0,rho) = 0.25 + asin(rho) / (2*pi) # V = L(h,0,rho) - asin(rho)/(2*pi) - Q(h) / 2 Lh0rho <- mvtnorm::pmvnorm( lower = c(h,0), upper = c(Inf,Inf), mean = c(0,0), corr = matrix(c(1,rho,rho,1),2,2) ) Qh <- pnorm(h, mean = 0, sd = 1, lower.tail = FALSE) return(Lh0rho - asin(rho)/2/pi - Qh/2) } polyCub/R/plotpolyf.R0000644000176000001440000000757512411527761014317 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2013-2014 Sebastian Meyer ### Time-stamp: <[plotpolyf.R] 2014-09-27 14:39 (CEST) by SM> ### ### Plot polygonal domain with image of bivariate function ################################################################################ ##' Plot Polygonal Domain on Image of Bivariate Function ##' ##' Produces a combined plot of a polygonal domain and an image of a bivariate ##' function, using either \code{\link[lattice:levelplot]{lattice::levelplot}} ##' or \code{\link{image}}. ##' ##' @param polyregion a polygonal domain. ##' The following classes are supported: \code{"\link[spatstat]{owin}"}, ##' \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"}, ##' \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, ##' and \code{"\linkS4class{Polygon}"} ##' (for these we have an internal \code{\link{xylist}} method). ##' @param f a two-dimensional real function. ##' As its first argument it must take a coordinate matrix, i.e., a ##' numeric matrix with two columns, and it must return a numeric vector of ##' length the number of coordinates. ##' @param ... further arguments for \code{f}. ##' @param npixel numeric vector of length 1 or 2 setting the number of pixels ##' in each dimension. ##' @param cuts number of cut points in the \eqn{z} dimension. ##' The range of function values will be divided into \code{cuts+1} levels. ##' @param col colour vector used for the function levels. ##' @param lwd line width of the polygon edges. ##' @param xlim,ylim numeric vectors of length 2 setting the axis limits. ##' \code{NULL} means using the bounding box of \code{polyregion}. ##' @param use.lattice logical indicating if \pkg{lattice} graphics ##' (\code{\link[lattice]{levelplot}}) should be used. ##' @param print.args a list of arguments passed to \code{\link{print.trellis}} ##' for plotting the produced \code{\link[=trellis.object]{"trellis"}} object ##' (given \code{use.lattice = TRUE}). The latter will be returned without ##' explicit \code{print}ing if \code{print.args} is not a list. ##' @author Sebastian Meyer ##' @keywords hplot ##' @example inst/examples/plotpolyf.R ##' @importFrom grDevices extendrange heat.colors ##' @importFrom graphics image ##' @export plotpolyf <- function (polyregion, f, ..., npixel=100, cuts=15, col=rev(heat.colors(cuts+1)), lwd=3, xlim=NULL, ylim=NULL, use.lattice=TRUE, print.args=list()) { polys <- xylist(polyregion) npixel <- rep(npixel, length.out=2) ## make two-dimensional grid if (is.null(xlim)) xlim <- extendrange(unlist(lapply(polys, "[[", "x"), use.names=FALSE)) if (is.null(ylim)) ylim <- extendrange(unlist(lapply(polys, "[[", "y"), use.names=FALSE)) xgrid <- makegrid(xlim, npixel[1]) ygrid <- makegrid(ylim, npixel[2]) xygrid <- expand.grid(x=xgrid, y=ygrid, KEEP.OUT.ATTRS=FALSE) ## compute function values on the grid xygrid$fval <- f(as.matrix(xygrid, rownames.force = FALSE), ...) ## plot if (use.lattice && requireNamespace("lattice")) { mypanel <- function(...) { lattice::panel.levelplot(...) lapply(polys, function(xy) lattice::panel.polygon(xy, lwd=lwd)) } trobj <- lattice::levelplot(fval ~ x*y, data=xygrid, aspect="iso", cuts=cuts, col.regions=col, panel=mypanel) if (is.list(print.args)) { do.call("print", c(alist(x=trobj), print.args)) } else trobj } else { image(xgrid, ygrid, matrix(xygrid$fval, npixel[1], npixel[2]), col=col, xlab="x", ylab="y", asp=1) plot_polyregion(polyregion, lwd=lwd, add=TRUE) } } polyCub/R/tools.R0000644000176000001440000000667312411476127013424 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2014 Sebastian Meyer ### Time-stamp: <[tools.R] 2014-09-27 10:59 (CEST) by SM> ### ### Tiny toolbox of internal function ################################################################################ ##' Check if Polygon is Closed ##' ##' Check if the first and last coordinates of a coordinate matrix are ##' identical. ##' @param coords numeric coordinate matrix. It is interpreted by ##' \code{\link{xy.coords}}. ##' @return logical ##' @keywords spatial internal ##' @importFrom grDevices xy.coords isClosed <- function (coords) { xycoords <- xy.coords(coords)[c("x","y")] n <- length(xycoords$x) return(identical(xycoords$x[1], xycoords$x[n]) && identical(xycoords$y[1], xycoords$y[n])) } ##' Dot/Scalar Product of Two Vectors ##' ##' This is nothing else than \code{sum(x*y)}. ##' @param x,y numeric vectors (of compatible lengths). ##' @return \code{sum(x*y)} ##' @keywords math internal dotprod <- function (x,y) sum(x*y) ##' Euclidean Vector Norm (Length) ##' ##' This is nothing else than \code{sqrt(sum(x^2))}. ##' @param x numeric vector. ##' @return \code{sqrt(sum(x^2))} ##' @keywords math internal vecnorm <- function (x) sqrt(sum(x^2)) ##' Checks if Argument is Scalar ##' ##' Check if the argument is scalar, i.e. a numeric vector of length 1. ##' @param x any object ##' @return logical ##' @keywords internal isScalar <- function (x) { length(x) == 1L && is.vector(x, mode = "numeric") } ##' Plots a Polygonal Domain (of Various Classes) ##' ##' @inheritParams plotpolyf ##' @param add logical. Add to existing plot? ##' @import methods ##' @import sp ##' @importFrom graphics polygon ##' @importFrom spatstat plot.owin ## CAVE: need to import plot.owin for compatibility with spatstat <1.33-0, ## since plot.owin was not registered as an S3-method for plot ## NOTE: we don't import graphics::plot since it is already imported via sp plot_polyregion <- function (polyregion, lwd=2, add=FALSE) { if (is.vector(polyregion, mode="list")) { # internal xylist object stopifnot(add) lapply(polyregion, polygon, lwd=lwd) invisible() } else if (inherits(polyregion, "gpc.poly")) { if (!isClass("gpc.poly")) library("rgeos") # probably redundant plot(polyregion, poly.args=list(lwd=lwd), ann=FALSE, add=add) } else { if (inherits(polyregion, "Polygon")) polyregion <- Polygons(list(polyregion), "ID") if (inherits(polyregion, "Polygons")) polyregion <- SpatialPolygons(list(polyregion)) ## plot call which works for "SpatialPolygons" and "owin" plot(polyregion, lwd=lwd, axes=TRUE, main="", add=add) } } ##' Constructs Equally-Spaced Grid ##' ##' Construct an equally-spaced grid given a range and the number of cut points ##' (one more than the number of resulting bins). ##' This is nothing else than \code{seq(range[1], range[2], length.out=n)}. ##' @param range numeric vector of length 2. ##' @param n length of the desired grid, i.e. number of bins + 1. ##' @return the desired grid, a numeric vector of length \code{n} covering ##' \code{range}. ##' @keywords internal makegrid <- function(range, n) seq(range[1], range[2], length.out=n) polyCub/R/coerce-gpc-methods.R0000644000176000001440000001006312422164573015721 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2012-2014 Sebastian Meyer ### Time-stamp: <[coerce-gpc-methods.R] 2014-10-23 13:41 (CEST) by SM> ### ### Conversion from and to the "gpc.poly" class ################################################################################ ##' Conversion from and to the \code{"gpc.poly"} Class ##' ##' Package \pkg{polyCub} implements converters between the classes ##' \code{"\link[spatstat:owin.object]{owin}"} of package \pkg{spatstat} and ##' \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} of package \pkg{rgeos} ##' (originally from \pkg{gpclib}). ##' Support for the \code{"gpc.poly"} class was dropped from ##' \pkg{spatstat} as of version 1.34-0. ##' ##' @param object an object of class \code{"gpc.poly"} or \code{"owin"}, ##' respectively. ##' @return The converted polygon of class \code{"gpc.poly"} or \code{"owin"}, ##' respectively. If neither package \pkg{rgeos} nor \pkg{gpclib} are available, ##' \code{owin2gpc} will just return the \code{pts} slot of the ##' \code{"gpc.poly"} (no formal class) with a warning. ##' @author Sebastian Meyer ##' @note The converter \code{owin2gpc} requires the package \pkg{rgeos} (or ##' \pkg{gpclib}) for the formal class definition of a \code{"gpc.poly"}. ##' It will produce vertices ordered according to the \pkg{sp} convention, ##' i.e. clockwise for normal boundaries and anticlockwise for holes, where, ##' however, the first vertex is \emph{not} repeated! ##' @seealso \code{\link{xylist}}, and the package \pkg{rgeos} for ##' conversions of \code{"gpc.poly"} objects from and to \pkg{sp}'s ##' \code{"\linkS4class{SpatialPolygons}"} class. ##' @rdname coerce-gpc-methods ##' @keywords spatial methods ##' @importFrom spatstat as.polygonal summary.owin ##' @import methods ##' @export owin2gpc <- function (object) { object <- as.polygonal(object) ## FIXME: spatstat functions to extract the areas and hole flags ## of the individual polygons in a polygonal "owin" would be nice holes <- summary.owin(object)$areas < 0 ## reverse vertices and set hole flags pts <- mapply( FUN = function (poly, hole) { list(x = rev(poly$x), y = rev(poly$y), hole = hole) ## or hole = area.owin(owin(poly = poly, check = FALSE)) < 0, ## but spatstat::is.hole.xypolygon is marked as an internal function }, poly = object$bdry, hole = holes, SIMPLIFY = FALSE, USE.NAMES = FALSE) ## formal class if (know_gpc.poly()) { new("gpc.poly", pts = pts) } else { warning("formal class \"gpc.poly\" not available") pts } } ##' @inheritParams owin2gpc ##' @param ... further arguments passed to \code{\link{owin}}. ##' @rdname coerce-gpc-methods ##' @importFrom spatstat owin summary.owin ##' @export gpc2owin <- function (object, ...) { ## first convert to an "owin" without checking areas etc. ## to determine the hole status according to vertex order (area) res <- owin(poly = object@pts, check = FALSE) holes_owin <- summary.owin(res)$areas < 0 ## Note: cannot rely on spatstat::Area.xypolygon since it is marked internal ## now fix the vertex order bdry <- mapply( FUN = function (poly, owinhole) { if (poly$hole != owinhole) { poly$x <- rev(poly$x) poly$y <- rev(poly$y) } poly }, poly = object@pts, owinhole = holes_owin, SIMPLIFY = FALSE, USE.NAMES = FALSE) ## now really convert to owin with appropriate vertex order owin(poly = bdry, ...) } ## check for the formal class "gpc.poly" (loading rgeos or gpclib if necessary) ##' @import methods know_gpc.poly <- function () { isClass("gpc.poly") || suppressWarnings(requireNamespace("rgeos", quietly=TRUE) || requireNamespace("gpclib", quietly=TRUE)) } polyCub/R/circleCub.R0000644000176000001440000000454412332113461014141 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2013-2014 Sebastian Meyer ### Time-stamp: <[circleCub.R] by SM Die 06/05/2014 10:02 (CEST)> ### ### Special cases of cubature over circular domains (center, r) ################################################################################ ##' Integration of the Isotropic Gaussian Density over Circular Domains ##' ##' This function calculates the integral of the bivariate, isotropic Gaussian ##' density (i.e. \eqn{\Sigma} = \code{sd^2*diag(2)}) over circular domains via ##' the cumulative distribution function of the (non-central) Chi-Squared ##' distribution (\code{pchisq}), cp. Formula 26.3.24 in Abramowitz and Stegun ##' (1972). ##' ##' @references ##' Abramowitz, M. and Stegun, I. A. (1972). ##' Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical ##' Tables. New York: Dover Publications. ##' @param center numeric vector of length 2 (center of the circle). ##' @param r numeric (radius of the circle). Several radii may be supplied. ##' @param mean numeric vector of length 2 ##' (mean of the bivariate Gaussian density). ##' @param sd numeric (common standard deviation of the isotropic ##' Gaussian density in both dimensions). ##' @return The integral value (one for each supplied radius). ##' @note The non-centrality parameter of the evaluated chi-squared distribution ##' equals the squared distance between the \code{mean} and the ##' \code{center}. If this becomes too large, the result becomes inaccurate, see ##' \code{\link{pchisq}}. ##' @keywords math spatial ##' @importFrom stats pchisq ##' @export ##' @examples ##' circleCub.Gauss(center=c(1,2), r=3, mean=c(4,5), sd=6) ##' ##' if (requireNamespace("mvtnorm") && gpclibPermit()) { ##' ## compare with cubature over a polygonal approximation of a circle ##' disc.poly <- spatstat::disc(radius=3, centre=c(1,2), npoly=32) ##' polyCub.exact.Gauss(disc.poly, mean=c(4,5), Sigma=6^2*diag(2)) ##' } circleCub.Gauss <- function (center, r, mean, sd) { stopifnot(isScalar(sd), length(center) == 2, length(mean) == 2) pchisq((r/sd)^2, df=2, ncp=sum(((center-mean)/sd)^2)) } polyCub/R/zzz.R0000644000176000001440000001051512422413714013102 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2009-2014 Sebastian Meyer ### Time-stamp: <[zzz.R] 2014-10-24 11:11 (CEST) by SM> ### ### Package administration ################################################################################ #' Cubature over Polygonal Domains #' #' The \R package \pkg{polyCub} provides methods for \strong{cubature} #' (numerical integration) \strong{over polygonal domains}. #' The function \code{\link{polyCub}()} is the main entry point of the package. #' It is a wrapper around the specific cubature methods listed below. #' #' \describe{ #' \item{\code{\link{polyCub.midpoint}}:}{ #' Two-dimensional midpoint rule. #' Polygons are converted to binary pixel images #' using the \code{\link[spatstat]{as.im.function}} method from package #' \pkg{spatstat} (Baddeley and Turner, 2005). #' The integral is then obtained as the sum over #' (pixel area * f(pixel midpoint)). #' } #' \item{\code{\link{polyCub.SV}}:}{ #' Product Gauss cubature as proposed by Sommariva and Vianello (2007). #' } #' \item{\code{\link{polyCub.iso}}:}{ #' Efficient adaptive cubature for \emph{isotropic} functions via line #' \code{\link{integrate}()} along the polygon boundary, see Meyer and Held #' (2014, Supplement B, Section 2.4). #' } #' \item{\code{\link{polyCub.exact.Gauss}}:}{ #' Quasi-exact method specific to the integration of the \emph{bivariate Gaussian #' density} over polygonal domains. It is based on formulae from Chapter 26 of #' the Abramowitz and Stegun (1972) handbook, i.e. triangulation of the #' polygonal domain (using \code{\link[gpclib]{tristrip}} of package #' \pkg{gpclib}) and appropriate evaluations of #' \code{\link[mvtnorm]{pmvnorm}} from package \pkg{mvtnorm}. #' Note that there is also a function \code{\link{circleCub.Gauss}} #' to perform integration of the \emph{isotropic} Gaussian density over #' \emph{circular domains}. #' } #' } #' See Section 3.2 of Meyer (2010) for a more detailed description and benchmark #' experiment of some of the above cubature methods (and others). #' #' @references #' Abramowitz, M. and Stegun, I. A. (1972). #' Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical #' Tables. New York: Dover Publications. #' #' Baddeley, A. and Turner, R. (2005). #' \pkg{spatstat}: an \R package for analyzing spatial point patterns. #' \emph{Journal of Statistical Software}, \bold{12} (6), 1-42. #' #' Meyer, S. (2010). #' Spatio-Temporal Infectious Disease Epidemiology based on Point Processes. #' Master's Thesis, LMU Munich. #' Available as \url{http://epub.ub.uni-muenchen.de/11703/}. #' #' Meyer, S. and Held, L. (2014). #' Power-law models for infectious disease spread. #' \emph{The Annals of Applied Statistics}, \bold{8} (3), 1612-1639.\cr #' DOI-Link: \url{http://dx.doi.org/10.1214/14-AOAS743}, #' \href{http://arxiv.org/abs/1308.5115}{arXiv:1308.5115} #' #' Sommariva, A. and Vianello, M. (2007). #' Product Gauss cubature over polygons based on Green's integration formula. #' \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. #' @docType package #' @name polyCub-package #' @seealso The packages \pkg{cubature} and \pkg{R2Cuba}, which are more #' appropriate for cubature over simple hypercubes. NULL .Options <- new.env() .onLoad <- function (libname, pkgname) { .Options$gpclib <- FALSE } gpclibCheck <- function (fatal = TRUE) { gpclibOK <- .Options$gpclib if (!gpclibOK && fatal) { message("Note: The gpclib license is accepted by ", sQuote("gpclibPermit()"), ".") stop("acceptance of the gpclib license is required") } gpclibOK } ##' \pkg{gpclib} Licence Acceptance ##' ##' Similar to the handling in package \pkg{maptools}, these functions ##' explicitly accept the restricted \pkg{gpclib} licence (commercial use ##' prohibited) and report its acceptance status, respectively. ##' \pkg{gpclib} functionality is only required for ##' \code{\link{polyCub.exact.Gauss}}. ##' @export gpclibPermit <- function () { if (requireNamespace("gpclib")) .Options$gpclib <- TRUE gpclibPermitStatus() } ##' @rdname gpclibPermit ##' @export gpclibPermitStatus <- function () gpclibCheck(fatal=FALSE) polyCub/R/coerce-sp-methods.R0000644000176000001440000000535612236005553015576 0ustar ripleyusers################################################################################ ### Part of the R package "polyCub". ### Free software under the terms of the GNU General Public License, version 2, ### a copy of which is available at http://www.r-project.org/Licenses/. ### ### Copyright (C) 2012-2013 Sebastian Meyer ### Time-stamp: <[coerce-sp-methods.R] by SM Mon 04/11/2013 22:02 (CET)> ### ### Coerce "Polygons" to and from "owin" ################################################################################ ##' Coerce \code{"Polygons"} to \code{"owin"} ##' ##' Package \pkg{polyCub} also implements \code{coerce}-methods ##' (\code{as(object, Class)}) to convert ##' \code{"\link[sp:Polygons-class]{Polygons}"} ##' (or \code{"\link[sp:SpatialPolygons-class]{SpatialPolygons}"} or ##' \code{"\link[sp:Polygon-class]{Polygon}"}) to ##' \code{"\link[spatstat:owin.object]{owin}"}. ##' @author Sebastian Meyer ##' @keywords spatial methods ##' @name coerce-sp-methods ##' @rdname coerce-sp-methods ##' @exportMethod coerce NULL ## Register "owin" as class in S4 so we can define methods for it ##setClass("owin") ## -> no need to register "owin", since we depend on sp which does it ! ## Otherwise we would get the following warning upon package installation: ## Warning in .simpleDuplicateClass(def, prev) : ## the specification for class "owin" in package 'polyCub' seems ## equivalent to one from package 'sp' and is not turning on ## duplicate class definitions for this class ## Using setOldClass("owin") is incompatible with package "maptools", which ## does setClass("owin") _and_ exports this class! Specifically, loading ## library("polyCub"); library("maptools"); library("gpclib") ## in this order would not work (no idea why) throwing: ## Error : package slot missing from signature for generic ‘plot’ ## and classes gpc.poly, ANY ## cannot use with duplicate class names (the package may need to be ## re-installed) ## Error: package/namespace load failed for ‘gpclib’ ##' @name coerce,SpatialPolygons,owin-method ##' @rdname coerce-sp-methods ##' @importFrom spatstat owin setAs(from = "SpatialPolygons", to = "owin", def = function (from) owin(poly=xylist.SpatialPolygons(from))) ##' @name coerce,Polygons,owin-method ##' @rdname coerce-sp-methods ##' @importFrom spatstat owin setAs(from = "Polygons", to = "owin", def = function (from) owin(poly=xylist.Polygons(from))) ##' @name coerce,Polygon,owin-method ##' @rdname coerce-sp-methods ##' @importFrom spatstat owin setAs(from = "Polygon", to = "owin", def = function (from) owin(poly=xylist.Polygon(from))) ##' @name coerce,Polygon,Polygons-method ##' @rdname coerce-sp-methods setAs(from = "Polygon", to = "Polygons", def = function (from) Polygons(list(from), "Polygon")) polyCub/MD50000644000176000001440000000450512422436556012244 0ustar ripleyusers6609b0a354182f3c5199c4b6daee5fa0 *DESCRIPTION 97154f0de0925e1dbf825361e131b135 *NAMESPACE 0a60a7ee72d69596c5c42d0e8070e42b *R/circleCub.R 73d819b8a03187fdb63ea68243dfbc83 *R/coerce-gpc-methods.R 6a6a7f50b84c23f2e1a5cd506d07d571 *R/coerce-sp-methods.R 671d2d34604542e536dea2027789228b *R/plotpolyf.R 00f8503508c8fe19abb7e261193adff8 *R/polyCub.R aa861e5d56bbb3a5c63be1546a126f88 *R/polyCub.SV.R fdbb145967927448ab17a8f5110a6aeb *R/polyCub.exact.Gauss.R 614ebf2a2221290d47bce5e2e706e787 *R/polyCub.iso.R f8f84d3be74f5e68ea4c53be26b33a87 *R/polyCub.midpoint.R 75a1bb73253360d3ffdbb005b55f083f *R/sysdata.rda 03fbe60745af88e3a67e2c60cb6c49e2 *R/tools.R 2b9d4ec80dceefc2c31620f8c7824d98 *R/xylist.R a9f5580a4daa787b5c36804c61336084 *R/zzz.R 6c6761ed7b661300969252cdfdb4f461 *inst/CITATION 536bedc343b1d4e91eb0d8ac668b3576 *inst/NEWS.Rd a2e8c8c02633c62187d4b62c80ed7bde *inst/examples/plotpolyf.R 71c354b04903463684d7ee0c21afc397 *inst/examples/polyCub.R fec41191e00776d1cb4615e89d6e3612 *inst/examples/polyCub.iso.R fb743d5d57971021a62308f06cbd1b26 *man/checkintrfr.Rd e6652fde39bae6e2327ef32bab4619a9 *man/circleCub.Gauss.Rd 2cfb215413fde2d95597665c389f32e1 *man/coerce-gpc-methods.Rd e1dcc2e9fbb47761bbcb05bdcfafbe8e *man/coerce-sp-methods.Rd 7fceba3eef4882998e9bea11f8bb1818 *man/dotprod.Rd e05bb78fb1d3203445e6f9fd401ba146 *man/gpclibPermit.Rd 987b33a9bbcfcb947dcc81a581fd39f4 *man/isClosed.Rd 3b38d613bdc728f91ebc937a2283912f *man/isScalar.Rd f8c8bc62661cfc3379d3fd96d7ecd654 *man/makegrid.Rd 2d7545f359674d322a29a68a019b56e3 *man/plot_polyregion.Rd 2874654bd44065f64aed06377d32fed8 *man/plotpolyf.Rd fd52b02751a5b9a117822ea8fb37b161 *man/polyCub-package.Rd f5669ea8b06eb73d6ff1e1a5ebfaab84 *man/polyCub.Rd 8cc24769157d85fe4a95cd1e4002578c *man/polyCub.SV.Rd 380bc745238ad75ed137ab9705b5b4b7 *man/polyCub.exact.Gauss.Rd 9262be52c76c6ba84ea9c161f3539460 *man/polyCub.iso.Rd 5109a1efa71093629a07005c29399130 *man/polyCub.midpoint.Rd 58e2cd8c495d2c9ada12d407d28f00aa *man/polygauss.Rd ecc9176dd2d24a11f47362b306a2b552 *man/vecnorm.Rd 8434e6fff4689756286c476a9ab5d942 *man/xylist.Rd 06c60d127ba19c6f0d0e800d30bc7042 *src/polyCub.SV.c c4b8e3fbbae6ebd4c0a7c55c8752bc5a *tests/test-all.R 2651267c01b757c16538407e72cd8198 *tests/testthat/test-NWGL.R 139fab4bf64df4b4bc33d79587644976 *tests/testthat/test-polyCub.R c3465483980762cdba5275a781d914d3 *tests/testthat/test-regression.R polyCub/DESCRIPTION0000644000176000001440000000335612422436556013445 0ustar ripleyusersPackage: polyCub Title: Cubature over Polygonal Domains Version: 0.5-1 Date: 2014-10-24 Authors@R: c(person("Sebastian", "Meyer", email = "Sebastian.Meyer@ifspm.uzh.ch", role = c("aut","cre","trl")), person("Michael", "Hoehle", email = "Michael.Hoehle@stat.uni-muenchen.de", role = c("ths"))) Description: A package providing methods for cubature (numerical integration) over polygonal domains. Currently, four cubature methods are implemented: the two-dimensional midpoint rule as a simple wrapper around as.im.function() from package spatstat (Baddeley and Turner, 2005), the product Gauss cubature by Sommariva and Vianello (2007), an adaptive cubature for isotropic functions via line integrate() along the boundary (Meyer and Held, 2014), and quasi-exact methods specific to the integration of the bivariate Gaussian density over polygonal and circular domains (based on formulae from the Abramowitz and Stegun (1972) handbook). For cubature over simple hypercubes, the packages "cubature" and "R2Cuba" are more appropriate. License: GPL-2 URL: https://github.com/WastlM/polyCub BugReports: https://github.com/WastlM/polyCub/issues Depends: R (>= 2.15.0), methods, sp Imports: grDevices, graphics, stats, spatstat Suggests: lattice, testthat, mvtnorm, statmod, rgeos, gpclib Packaged: 2014-10-24 09:15:32 UTC; sebastian Author: Sebastian Meyer [aut, cre, trl], Michael Hoehle [ths] Maintainer: Sebastian Meyer NeedsCompilation: yes Repository: CRAN Date/Publication: 2014-10-24 13:52:14 polyCub/man/0000755000176000001440000000000012375634615012506 5ustar ripleyuserspolyCub/man/coerce-gpc-methods.Rd0000644000176000001440000000303612422164712016434 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{owin2gpc} \alias{gpc2owin} \alias{owin2gpc} \title{Conversion from and to the \code{"gpc.poly"} Class} \usage{ owin2gpc(object) gpc2owin(object, ...) } \arguments{ \item{object}{an object of class \code{"gpc.poly"} or \code{"owin"}, respectively.} \item{...}{further arguments passed to \code{\link{owin}}.} } \value{ The converted polygon of class \code{"gpc.poly"} or \code{"owin"}, respectively. If neither package \pkg{rgeos} nor \pkg{gpclib} are available, \code{owin2gpc} will just return the \code{pts} slot of the \code{"gpc.poly"} (no formal class) with a warning. } \description{ Package \pkg{polyCub} implements converters between the classes \code{"\link[spatstat:owin.object]{owin}"} of package \pkg{spatstat} and \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} of package \pkg{rgeos} (originally from \pkg{gpclib}). Support for the \code{"gpc.poly"} class was dropped from \pkg{spatstat} as of version 1.34-0. } \note{ The converter \code{owin2gpc} requires the package \pkg{rgeos} (or \pkg{gpclib}) for the formal class definition of a \code{"gpc.poly"}. It will produce vertices ordered according to the \pkg{sp} convention, i.e. clockwise for normal boundaries and anticlockwise for holes, where, however, the first vertex is \emph{not} repeated! } \author{ Sebastian Meyer } \seealso{ \code{\link{xylist}}, and the package \pkg{rgeos} for conversions of \code{"gpc.poly"} objects from and to \pkg{sp}'s \code{"\linkS4class{SpatialPolygons}"} class. } \keyword{methods} \keyword{spatial} polyCub/man/dotprod.Rd0000644000176000001440000000052112411522266014433 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{dotprod} \alias{dotprod} \title{Dot/Scalar Product of Two Vectors} \usage{ dotprod(x, y) } \arguments{ \item{x,y}{numeric vectors (of compatible lengths).} } \value{ \code{sum(x*y)} } \description{ This is nothing else than \code{sum(x*y)}. } \keyword{internal} \keyword{math} polyCub/man/polyCub.Rd0000644000176000001440000000664012411522266014405 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polyCub} \alias{polyCub} \title{Wrapper Function for the Various Cubature Methods} \usage{ polyCub(polyregion, f, method = c("SV", "midpoint", "iso", "exact.Gauss"), ..., plot = FALSE) } \arguments{ \item{polyregion}{a polygonal integration domain. The supported classes depend on the specific method, however, the \code{"\link[spatstat]{owin}"} class from package \pkg{spatstat} works for all methods, as well should a \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} polygon (but see the comments in \code{help("\link{coerce-methods}")}).} \item{f}{two-dimensional function to be integrated. As its first argument the function must take a coordinate matrix, i.e. a numeric matrix with two columns. For the \code{"exact.Gauss"} \code{method}, \code{f} is ignored since it is specific to the bivariate normal density.} \item{method}{choose one of the implemented cubature methods (partial argument matching is applied), see \code{help("\link{polyCub-package}")} for an overview. Defaults to using the product Gauss cubature implemented in \code{\link{polyCub.SV}}.} \item{...}{arguments of \code{f} or of the specific \code{method}.} \item{plot}{logical indicating if an illustrative plot of the numerical integration should be produced.} } \value{ The approximated integral of \code{f} over \code{polyregion}. } \description{ Instead of calling one of the specific cubature methods of this package, the wrapper function \code{polyCub} may be used together with the \code{method} argument. } \examples{ ### Short comparison of the various cubature methods ## 2D-function to integrate (here: isotropic zero-mean Gaussian density) f <- function (s, sigma = 5) exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2) ## simple polygonal integration domain disc.owin <- spatstat::disc(radius=5, centre=c(3,2), npoly=8) ## plot image of the function and integration domain plotpolyf(disc.owin, f, xlim=c(-8,8), ylim=c(-8,8)) ### Two-dimensional midpoint rule testmidpoint <- function (eps, main=paste("2D midpoint rule with eps =",eps)) { plotpolyf(disc.owin, f, xlim=c(-8,8), ylim=c(-8,8), use.lattice=FALSE) ## add evaluation points to plot with(spatstat::as.mask(disc.owin, eps=eps), points(expand.grid(xcol, yrow), col=m, pch=20)) polyCub.midpoint(disc.owin, f, eps=eps) } testmidpoint(5) testmidpoint(3) testmidpoint(0.5) testmidpoint(0.2) ### Product Gauss cubature using an increasing number of nodes for (nGQ in c(1:5,10,20,60)) { cat("nGQ =", sprintf("\%2i",nGQ), ": ", format(polyCub.SV(disc.owin, f, nGQ=nGQ), digits=16), "\\n") } ## 'rotation' affects location of nodes opar <- par(mfrow=c(1,2)) polyCub.SV(disc.owin, f, nGQ=2, rotation=FALSE, plot=TRUE) polyCub.SV(disc.owin, f, nGQ=2, rotation=TRUE, plot=TRUE) par(opar) ### Line integration along the boundary for isotropic functions polyCub.iso(disc.owin, f, center=c(0,0)) # see ?polyCub.iso ### Quasi-exact cubature of the bivariate Gaussian density ### using gpclib::tristrip and mvtnorm::pmvnorm() if (requireNamespace("mvtnorm") && gpclibPermit()) { print(polyCub.exact.Gauss(disc.owin, mean=c(0,0), Sigma=5^2*diag(2), plot=TRUE), digits=16) } } \seealso{ Other polyCub.methods: \code{\link{.polyCub.iso}}, \code{\link{polyCub.iso}}; \code{\link{polyCub.SV}}; \code{\link{polyCub.exact.Gauss}}; \code{\link{polyCub.midpoint}} } \keyword{math} \keyword{spatial} polyCub/man/plot_polyregion.Rd0000644000176000001440000000130212411522266016203 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{plot_polyregion} \alias{plot_polyregion} \title{Plots a Polygonal Domain (of Various Classes)} \usage{ plot_polyregion(polyregion, lwd = 2, add = FALSE) } \arguments{ \item{polyregion}{a polygonal domain. The following classes are supported: \code{"\link[spatstat]{owin}"}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"}, \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} (for these we have an internal \code{\link{xylist}} method).} \item{lwd}{line width of the polygon edges.} \item{add}{logical. Add to existing plot?} } \description{ Plots a Polygonal Domain (of Various Classes) } polyCub/man/vecnorm.Rd0000644000176000001440000000047412411522266014440 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{vecnorm} \alias{vecnorm} \title{Euclidean Vector Norm (Length)} \usage{ vecnorm(x) } \arguments{ \item{x}{numeric vector.} } \value{ \code{sqrt(sum(x^2))} } \description{ This is nothing else than \code{sqrt(sum(x^2))}. } \keyword{internal} \keyword{math} polyCub/man/polyCub-package.Rd0000644000176000001440000000553212422413727016000 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \docType{package} \name{polyCub-package} \alias{polyCub-package} \title{Cubature over Polygonal Domains} \description{ The \R package \pkg{polyCub} provides methods for \strong{cubature} (numerical integration) \strong{over polygonal domains}. The function \code{\link{polyCub}()} is the main entry point of the package. It is a wrapper around the specific cubature methods listed below. } \details{ \describe{ \item{\code{\link{polyCub.midpoint}}:}{ Two-dimensional midpoint rule. Polygons are converted to binary pixel images using the \code{\link[spatstat]{as.im.function}} method from package \pkg{spatstat} (Baddeley and Turner, 2005). The integral is then obtained as the sum over (pixel area * f(pixel midpoint)). } \item{\code{\link{polyCub.SV}}:}{ Product Gauss cubature as proposed by Sommariva and Vianello (2007). } \item{\code{\link{polyCub.iso}}:}{ Efficient adaptive cubature for \emph{isotropic} functions via line \code{\link{integrate}()} along the polygon boundary, see Meyer and Held (2014, Supplement B, Section 2.4). } \item{\code{\link{polyCub.exact.Gauss}}:}{ Quasi-exact method specific to the integration of the \emph{bivariate Gaussian density} over polygonal domains. It is based on formulae from Chapter 26 of the Abramowitz and Stegun (1972) handbook, i.e. triangulation of the polygonal domain (using \code{\link[gpclib]{tristrip}} of package \pkg{gpclib}) and appropriate evaluations of \code{\link[mvtnorm]{pmvnorm}} from package \pkg{mvtnorm}. Note that there is also a function \code{\link{circleCub.Gauss}} to perform integration of the \emph{isotropic} Gaussian density over \emph{circular domains}. } } See Section 3.2 of Meyer (2010) for a more detailed description and benchmark experiment of some of the above cubature methods (and others). } \references{ Abramowitz, M. and Stegun, I. A. (1972). Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables. New York: Dover Publications. Baddeley, A. and Turner, R. (2005). \pkg{spatstat}: an \R package for analyzing spatial point patterns. \emph{Journal of Statistical Software}, \bold{12} (6), 1-42. Meyer, S. (2010). Spatio-Temporal Infectious Disease Epidemiology based on Point Processes. Master's Thesis, LMU Munich. Available as \url{http://epub.ub.uni-muenchen.de/11703/}. Meyer, S. and Held, L. (2014). Power-law models for infectious disease spread. \emph{The Annals of Applied Statistics}, \bold{8} (3), 1612-1639.\cr DOI-Link: \url{http://dx.doi.org/10.1214/14-AOAS743}, \href{http://arxiv.org/abs/1308.5115}{arXiv:1308.5115} Sommariva, A. and Vianello, M. (2007). Product Gauss cubature over polygons based on Green's integration formula. \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. } \seealso{ The packages \pkg{cubature} and \pkg{R2Cuba}, which are more appropriate for cubature over simple hypercubes. } polyCub/man/checkintrfr.Rd0000644000176000001440000000334512411522266015271 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{checkintrfr} \alias{checkintrfr} \title{Check the Integral of \eqn{r f_r(r)}} \usage{ checkintrfr(intrfr, f, ..., center, control = list(), rs = numeric(0L), tolerance = control$rel.tol) } \arguments{ \item{intrfr}{analytical antiderivative of \eqn{r f_r(r)} from 0 to \code{R} (first argument, not necessarily named \code{"R"}, must be vectorized). If missing, \code{intrfr} is approximated numerically using \code{\link{integrate}} configured with \code{control}.} \item{f}{a two-dimensional real function. As its first argument it must take a coordinate matrix, i.e., a numeric matrix with two columns, and it must return a numeric vector of length the number of coordinates.} \item{...}{further arguments for \code{f} or \code{intrfr}.} \item{center}{numeric vector of length 2, the center of isotropy.} \item{control}{list of arguments passed to \code{\link{integrate}}, the quadrature rule used for the line integral along the polygon boundary.} \item{rs}{numeric vector of upper bounds for which to check the validity of \code{intrfr}. If it has length 0, no checks are performed.} \item{tolerance}{of \code{\link{all.equal.numeric}} when comparing \code{intrfr} results with numerical integration. Defaults to the relative tolerance used for \code{integrate}.} } \value{ The \code{intrfr} function. If it was not supplied, its quadrature version using \code{integrate} is returned. } \description{ This function is auxiliary to \code{\link{polyCub.iso}}. The (analytical) integral of \eqn{r f_r(r)} from 0 to \eqn{R} is checked against a numeric approximation using \code{\link{integrate}} for various values of the upper bound \eqn{R}. A warning is issued if inconsistencies are found. } polyCub/man/polyCub.exact.Gauss.Rd0000644000176000001440000000555412411522266016574 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polyCub.exact.Gauss} \alias{polyCub.exact.Gauss} \title{Quasi-Exact Cubature of the Bivariate Normal Density} \usage{ polyCub.exact.Gauss(polyregion, mean = c(0, 0), Sigma = diag(2), plot = FALSE) } \arguments{ \item{polyregion}{a \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} polygon or something that can be coerced to this class, e.g., an \code{"owin"} polygon (converted via \code{\link{owin2gpc}} and -- given \pkg{rgeos} is available -- \code{"SpatialPolygons"} also work.} \item{mean,Sigma}{mean and covariance matrix of the bivariate normal density to be integrated.} \item{plot}{logical indicating if an illustrative plot of the numerical integration should be produced. Note that the \code{polyregion} will be shifted and scaled.} } \value{ The integral of the bivariate normal density over \code{polyregion}. Two attributes are appended to the integral value: \item{nEval}{ number of triangles over which the standard bivariate normal density had to be integrated, i.e. number of calls to \code{\link[mvtnorm]{pmvnorm}} and \code{\link[stats]{pnorm}}, the former of which being the most time-consuming operation. } \item{error}{ Approximate absolute integration error steming from the error introduced by the \code{nEval} \code{\link[mvtnorm]{pmvnorm}} evaluations. For this reason, the cubature method is in fact only quasi-exact (as is the \code{pmvnorm} function). } } \description{ Integration is based on triangulation of the polygonal domain and formulae from the Abramowitz and Stegun (1972) handbook (Section 26.9, Example 9, pp. 956f.). This method is quite cumbersome because the A&S formula is only for triangles where one vertex is the origin (0,0). For each triangle of the \code{\link[gpclib]{tristrip}} we have to check in which of the 6 outer regions of the triangle the origin (0,0) lies and adapt the signs in the formula appropriately. (AOB+BOC-AOC) or (AOB-AOC-BOC) or (AOB+AOC-BOC) or (AOC+BOC-AOB) or \ldots. However, the most time consuming step is the evaluation of \code{\link[mvtnorm]{pmvnorm}}. } \note{ The package \pkg{gpclib} (which is required to produce the \code{tristrip}, since this is not yet implemented in \pkg{rgeos}) has a restricted license (commercial use prohibited). It has to be accepted explicitly via \code{\link{gpclibPermit}()} prior to using \code{polyCub.exact.Gauss}. } \examples{ # see example(polyCub) } \references{ Abramowitz, M. and Stegun, I. A. (1972). Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables. New York: Dover Publications. } \seealso{ \code{\link{circleCub.Gauss}} for quasi-exact cubature of the isotropic Gaussian density over a circular domain. Other polyCub.methods: \code{\link{.polyCub.iso}}, \code{\link{polyCub.iso}}; \code{\link{polyCub.SV}}; \code{\link{polyCub.midpoint}}; \code{\link{polyCub}} } \keyword{math} \keyword{spatial} polyCub/man/circleCub.Gauss.Rd0000644000176000001440000000325512411522266015743 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{circleCub.Gauss} \alias{circleCub.Gauss} \title{Integration of the Isotropic Gaussian Density over Circular Domains} \usage{ circleCub.Gauss(center, r, mean, sd) } \arguments{ \item{center}{numeric vector of length 2 (center of the circle).} \item{r}{numeric (radius of the circle). Several radii may be supplied.} \item{mean}{numeric vector of length 2 (mean of the bivariate Gaussian density).} \item{sd}{numeric (common standard deviation of the isotropic Gaussian density in both dimensions).} } \value{ The integral value (one for each supplied radius). } \description{ This function calculates the integral of the bivariate, isotropic Gaussian density (i.e. \eqn{\Sigma} = \code{sd^2*diag(2)}) over circular domains via the cumulative distribution function of the (non-central) Chi-Squared distribution (\code{pchisq}), cp. Formula 26.3.24 in Abramowitz and Stegun (1972). } \note{ The non-centrality parameter of the evaluated chi-squared distribution equals the squared distance between the \code{mean} and the \code{center}. If this becomes too large, the result becomes inaccurate, see \code{\link{pchisq}}. } \examples{ circleCub.Gauss(center=c(1,2), r=3, mean=c(4,5), sd=6) if (requireNamespace("mvtnorm") && gpclibPermit()) { ## compare with cubature over a polygonal approximation of a circle disc.poly <- spatstat::disc(radius=3, centre=c(1,2), npoly=32) polyCub.exact.Gauss(disc.poly, mean=c(4,5), Sigma=6^2*diag(2)) } } \references{ Abramowitz, M. and Stegun, I. A. (1972). Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables. New York: Dover Publications. } \keyword{math} \keyword{spatial} polyCub/man/polyCub.midpoint.Rd0000644000176000001440000000334612411522266016227 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polyCub.midpoint} \alias{polyCub.midpoint} \title{Two-Dimensional Midpoint Rule} \usage{ polyCub.midpoint(polyregion, f, ..., eps = NULL, dimyx = NULL, plot = FALSE) } \arguments{ \item{polyregion}{a polygonal integration domain. It can be any object coercible to the \pkg{spatstat} class \code{"\link[spatstat]{owin}"} (via \code{\link[spatstat]{as.owin}}).} \item{f}{a two-dimensional real function. As its first argument it must take a coordinate matrix, i.e., a numeric matrix with two columns, and it must return a numeric vector of length the number of coordinates.} \item{...}{further arguments for \code{f}.} \item{eps}{width and height of the pixels (squares), see \code{\link[spatstat]{as.mask}}.} \item{dimyx}{number of subdivisions in each dimension, see \code{\link[spatstat]{as.mask}}.} \item{plot}{logical indicating if an illustrative plot of the numerical integration should be produced.} } \value{ The approximated value of the integral of \code{f} over \code{polyregion}. } \description{ The surface is converted to a binary pixel image using the \code{\link[spatstat]{as.im.function}} method from package \pkg{spatstat} (Baddeley and Turner, 2005). The integral under the surface is then approximated as the sum over (pixel area * f(pixel midpoint)). } \examples{ # see example(polyCub) } \references{ Baddeley, A. and Turner, R. (2005). \pkg{spatstat}: an \R package for analyzing spatial point patterns. \emph{Journal of Statistical Software}, \bold{12} (6), 1-42. } \seealso{ Other polyCub.methods: \code{\link{.polyCub.iso}}, \code{\link{polyCub.iso}}; \code{\link{polyCub.SV}}; \code{\link{polyCub.exact.Gauss}}; \code{\link{polyCub}} } \keyword{math} \keyword{spatial} polyCub/man/polyCub.iso.Rd0000644000176000001440000001170312422413727015175 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polyCub.iso} \alias{.polyCub.iso} \alias{polyCub.iso} \title{Cubature of Isotropic Functions over Polygonal Domains} \usage{ polyCub.iso(polyregion, f, intrfr, ..., center, control = list(), check.intrfr = FALSE, plot = FALSE) .polyCub.iso(polys, intrfr, ..., center, control = list(), .witherror = FALSE) } \arguments{ \item{polyregion}{a polygonal domain. The following classes are supported: \code{"\link[spatstat]{owin}"}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"}, \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} (for these we have an internal \code{\link{xylist}} method).} \item{f}{a two-dimensional real function. As its first argument it must take a coordinate matrix, i.e., a numeric matrix with two columns, and it must return a numeric vector of length the number of coordinates.} \item{intrfr}{analytical antiderivative of \eqn{r f_r(r)} from 0 to \code{R} (first argument, not necessarily named \code{"R"}, must be vectorized). If missing, \code{intrfr} is approximated numerically using \code{\link{integrate}} configured with \code{control}.} \item{...}{further arguments for \code{f} or \code{intrfr}.} \item{center}{numeric vector of length 2, the center of isotropy.} \item{control}{list of arguments passed to \code{\link{integrate}}, the quadrature rule used for the line integral along the polygon boundary.} \item{check.intrfr}{logical (or numeric vector) indicating if (for which \code{r}'s) the supplied \code{intrfr} function should be checked against a numeric approximation. This check requires \code{f} to be specified. If \code{TRUE}, the set of test \code{r}'s defaults to a \code{\link{seq}} of length 20 from 1 to the maximum absolute x or y coordinate of any edge of the \code{polyregion}.} \item{plot}{logical indicating if an image of the function should be plotted together with the polygonal domain, i.e., \code{\link{plotpolyf}(polyregion, f, \dots)}.} \item{polys}{something like \code{owin$bdry}, but see \code{\link{xylist}}.} \item{.witherror}{logical indicating if an upperbound for the absolute integration error should be attached as an attribute to the result?} } \value{ The approximate integral of the isotropic function \code{f} over \code{polyregion}.\cr If the \code{intrfr} function is provided (which is assumed to be exact), an upperbound for the absolute integration error is appended to the result as attribute \code{"abs.error"}. It equals the sum of the absolute errors reported by all \code{\link{integrate}} calls (there is one for each edge of \code{polyregion}). } \description{ Conducts numerical integration of a two-dimensional isotropic function \eqn{f(x,y) = f_r(||(x,y)-\boldsymbol{\mu}||)}{f(x,y) = f_r(||(x,y)-\mu||)}, with \eqn{\mu} being the center of isotropy, over a polygonal domain. It internally solves a line integral along the polygon boundary using \code{\link{integrate}} where the integrand requires the antiderivative of \eqn{r f_r(r)}), which ideally is analytically available and supplied to the function as argument \code{intrfr}. The two-dimensional integration problem thereby reduces to an efficient adaptive quadrature in one dimension. See Meyer and Held (2014, Supplement B, Section 2.4) for mathematical details. \code{.polyCub.iso} is a \dQuote{bare-bone} version of \code{polyCub.iso}. } \examples{ ## we use the example polygon and f (exponential decay) from example(plotpolyf) ## numerical approximation of 'intrfr' (intISOnum <- polyCub.iso(letterR, f, center=fcenter)) ## analytical 'intrfr' (recall: f_r(r)=dexp(r), we need int_0^R r*f(r) dr) intrfr <- function (R, rate=1) pgamma(R, 2, rate) / rate (intISOana <- polyCub.iso(letterR, intrfr=intrfr, center=fcenter)) stopifnot(all.equal(intISOana, intISOnum, check.attributes=FALSE)) ### polygon area: f(r) = 1, f(x,y) = 1, center does not really matter intrfr.const <- function (R) R^2/2 (area.ISO <- polyCub.iso(letterR, intrfr=intrfr.const, center=c(0,0))) stopifnot(all.equal(spatstat::area.owin(letterR), area.ISO, check.attributes=FALSE)) ## the hole is subtracted correctly } \author{ Sebastian Meyer The basic mathematical formulation of this efficient integration for radially symmetric functions was ascertained with great support by Emil Hedevang (2013), Dept. of Mathematics, Aarhus University, Denmark. } \references{ Hedevang, E. (2013). Personal communication at the Summer School on Topics in Space-Time Modeling and Inference (May 2013, Aalborg, Denmark). Meyer, S. and Held, L. (2014). Power-law models for infectious disease spread. \emph{The Annals of Applied Statistics}, \bold{8} (3), 1612-1639.\cr DOI-Link: \url{http://dx.doi.org/10.1214/14-AOAS743}, \href{http://arxiv.org/abs/1308.5115}{arXiv:1308.5115} } \seealso{ Other polyCub.methods: \code{\link{polyCub.SV}}; \code{\link{polyCub.exact.Gauss}}; \code{\link{polyCub.midpoint}}; \code{\link{polyCub}} } \keyword{math} \keyword{spatial} polyCub/man/xylist.Rd0000644000176000001440000000574012422163007014320 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{xylist} \alias{xylist} \alias{xylist.Polygon} \alias{xylist.Polygons} \alias{xylist.SpatialPolygons} \alias{xylist.default} \alias{xylist.gpc.poly} \alias{xylist.owin} \title{Convert Various Polygon Classes to a Simple List of Vertices} \usage{ xylist(object, ...) \method{xylist}{owin}(object, ...) \method{xylist}{gpc.poly}(object, ...) \method{xylist}{SpatialPolygons}(object, reverse = TRUE, ...) \method{xylist}{Polygons}(object, reverse = TRUE, ...) \method{xylist}{Polygon}(object, reverse = TRUE, ...) \method{xylist}{default}(object, ...) } \arguments{ \item{object}{an object of one of the supported spatial classes.} \item{...}{(unused) argument of the generic.} \item{reverse}{logical (\code{TRUE}) indicating if the vertex order of the \pkg{sp} classes should be reversed to get the \code{xylist}/\code{owin} convention.} } \value{ Applying \code{xylist} to a polygon object, one gets a simple list, where each component (polygon) is a list of \code{"x"} and \code{"y"} coordinates. These represent vertex coordinates following \pkg{spatstat}'s \code{"owin"} convention (anticlockwise order without repeating any vertex). The opposite vertex order can be retained for the \pkg{sp}-classes by the non-default use with \code{reverse=FALSE}. } \description{ Different packages concerned with spatial data use different polygon specifications, which sometimes becomes very confusing (see Details below). To be compatible with the various polygon classes, package \pkg{polyCub} uses an S3 class \code{"xylist"}, which represents polygons by their core feature only, a list of lists of vertex coordinates (see the "Value" section below). The generic function \code{xylist} can deal with the following polygon classes: \itemize{ \item{\code{"\link[spatstat:owin.object]{owin}"} from package \pkg{spatstat}} \item{\code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from package \pkg{rgeos} (or \pkg{gpclib})} \item{\code{"\link[sp:Polygons-class]{Polygons}"} from package \pkg{sp} (as well as \code{"\link[sp:Polygon-class]{Polygon}"} and \code{"\link[sp:SpatialPolygons-class]{SpatialPolygons}"})} } The (somehow useless) default \code{xylist}-method does not perform any transformation but only ensures that the polygons are not closed (first vertex not repeated). } \details{ Different packages concerned with spatial data use different polygon specifications with respect to: \itemize{ \item{do we repeat the first vertex?} \item{which direction represents holes?} } Package overview: \describe{ \item{\pkg{sp}:}{\emph{Repeat} first vertex at the end (closed), anticlockwise = hole, clockwise = normal boundary} \item{\pkg{spatstat}:}{do \emph{not repeat} first vertex, anticlockwise = normal boundary, clockwise = hole. This convention is also used in \code{xylist}.} \item{\pkg{gpclib}:}{Unfortunately, there seems to be no convention for the specification of polygons of class \code{"gpc.poly"}.} } } \author{ Sebastian Meyer } \keyword{methods} \keyword{spatial} polyCub/man/makegrid.Rd0000644000176000001440000000111712411522266014545 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{makegrid} \alias{makegrid} \title{Constructs Equally-Spaced Grid} \usage{ makegrid(range, n) } \arguments{ \item{range}{numeric vector of length 2.} \item{n}{length of the desired grid, i.e. number of bins + 1.} } \value{ the desired grid, a numeric vector of length \code{n} covering \code{range}. } \description{ Construct an equally-spaced grid given a range and the number of cut points (one more than the number of resulting bins). This is nothing else than \code{seq(range[1], range[2], length.out=n)}. } \keyword{internal} polyCub/man/polygauss.Rd0000644000176000001440000000514612411525202015007 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polygauss} \alias{polygauss} \title{Calculate 2D Nodes and Weights of the Product Gauss Cubature} \usage{ polygauss(xy, nw_MN, alpha = NULL, rotation = FALSE, engine = "C") } \arguments{ \item{xy}{list with elements \code{"x"} and \code{"y"} containing the polygon vertices in \emph{anticlockwise} order (otherwise the result of the cubature will have a negative sign) with first vertex not repeated at the end (like \code{owin.object$bdry}).} \item{nw_MN}{unnamed list of nodes and weights of one-dimensional Gauss quadrature rules of degrees \eqn{N} and \eqn{M=N+1} (as returned by \code{\link[statmod]{gauss.quad}}): \code{list(s_M, w_M, s_N, w_N)}.} \item{alpha}{base-line of the (rotated) polygon at \eqn{x = \alpha} (see Sommariva and Vianello (2007) for an explication). If \code{NULL} (default), the midpoint of the x-range of each polygon is chosen if no \code{rotation} is performed, and otherwise the \eqn{x}-coordinate of the rotated point \code{"P"} (see \code{rotation}). If \code{f} has its maximum value at the origin \eqn{(0,0)}, e.g., the bivariate Gaussian density with zero mean, \code{alpha = 0} is a reasonable choice.} \item{rotation}{logical (default: \code{FALSE}) or a list of points \code{"P"} and \code{"Q"} describing the preferred direction. If \code{TRUE}, the polygon is rotated according to the vertices \code{"P"} and \code{"Q"}, which are farthest apart (see Sommariva and Vianello, 2007). For convex polygons, this rotation guarantees that all nodes fall inside the polygon.} \item{engine}{character string specifying the implementation to use. Up to \pkg{polyCub} version 0.4-3, the two-dimensional nodes and weights were computed by \R functions and these are still available by setting \code{engine = "R"}. The new C-implementation is now the default (\code{engine = "C"}) and requires approximately 30\% less computation time.\cr The special setting \code{engine = "C+reduce"} will discard redundant nodes at (0,0) with zero weight resulting from edges on the base-line \eqn{x = \alpha} or orthogonal to it. This extra cleaning is only worth its cost for computationally intensive functions \code{f} over polygons which really have some edges on the baseline or parallel to the x-axis. Note that the old \R implementation does not have such unset zero nodes and weights.} } \description{ Calculate 2D Nodes and Weights of the Product Gauss Cubature } \references{ Sommariva, A. and Vianello, M. (2007): Product Gauss cubature over polygons based on Green's integration formula. \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. } \keyword{internal} polyCub/man/plotpolyf.Rd0000644000176000001440000000447412411522266015023 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{plotpolyf} \alias{plotpolyf} \title{Plot Polygonal Domain on Image of Bivariate Function} \usage{ plotpolyf(polyregion, f, ..., npixel = 100, cuts = 15, col = rev(heat.colors(cuts + 1)), lwd = 3, xlim = NULL, ylim = NULL, use.lattice = TRUE, print.args = list()) } \arguments{ \item{polyregion}{a polygonal domain. The following classes are supported: \code{"\link[spatstat]{owin}"}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"}, \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} (for these we have an internal \code{\link{xylist}} method).} \item{f}{a two-dimensional real function. As its first argument it must take a coordinate matrix, i.e., a numeric matrix with two columns, and it must return a numeric vector of length the number of coordinates.} \item{...}{further arguments for \code{f}.} \item{npixel}{numeric vector of length 1 or 2 setting the number of pixels in each dimension.} \item{cuts}{number of cut points in the \eqn{z} dimension. The range of function values will be divided into \code{cuts+1} levels.} \item{col}{colour vector used for the function levels.} \item{lwd}{line width of the polygon edges.} \item{xlim,ylim}{numeric vectors of length 2 setting the axis limits. \code{NULL} means using the bounding box of \code{polyregion}.} \item{use.lattice}{logical indicating if \pkg{lattice} graphics (\code{\link[lattice]{levelplot}}) should be used.} \item{print.args}{a list of arguments passed to \code{\link{print.trellis}} for plotting the produced \code{\link[=trellis.object]{"trellis"}} object (given \code{use.lattice = TRUE}). The latter will be returned without explicit \code{print}ing if \code{print.args} is not a list.} } \description{ Produces a combined plot of a polygonal domain and an image of a bivariate function, using either \code{\link[lattice:levelplot]{lattice::levelplot}} or \code{\link{image}}. } \examples{ ### a polygonal domain data("letterR", package="spatstat") ### f: isotropic exponential decay fr <- function(r, rate=1) dexp(r, rate=rate) fcenter <- c(2,3) f <- function (s, rate=1) fr(sqrt(rowSums(t(t(s)-fcenter)^2)), rate=rate) ### plot plotpolyf(letterR, f, use.lattice=FALSE) plotpolyf(letterR, f, use.lattice=TRUE) } \author{ Sebastian Meyer } \keyword{hplot} polyCub/man/gpclibPermit.Rd0000644000176000001440000000077112411522266015410 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{gpclibPermit} \alias{gpclibPermit} \alias{gpclibPermitStatus} \title{\pkg{gpclib} Licence Acceptance} \usage{ gpclibPermit() gpclibPermitStatus() } \description{ Similar to the handling in package \pkg{maptools}, these functions explicitly accept the restricted \pkg{gpclib} licence (commercial use prohibited) and report its acceptance status, respectively. \pkg{gpclib} functionality is only required for \code{\link{polyCub.exact.Gauss}}. } polyCub/man/polyCub.SV.Rd0000644000176000001440000001015412411525202014720 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{polyCub.SV} \alias{polyCub.SV} \title{Product Gauss Cubature over Polygonal Domains} \usage{ polyCub.SV(polyregion, f, ..., nGQ = 20, alpha = NULL, rotation = FALSE, engine = "C", plot = FALSE) } \arguments{ \item{polyregion}{a polygonal domain. The following classes are supported: \code{"\link[spatstat]{owin}"}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"}, \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} (for these we have an internal \code{\link{xylist}} method).} \item{f}{a two-dimensional real function (or \code{NULL} to only compute nodes and weights). As its first argument it must take a coordinate matrix, i.e., a numeric matrix with two columns, and it must return a numeric vector of length the number of coordinates.} \item{...}{further arguments for \code{f}.} \item{nGQ}{degree of the one-dimensional Gauss-Legendre quadrature rule (default: 20) as implemented in function \code{\link[statmod]{gauss.quad}} of package \pkg{statmod}. Nodes and weights up to \code{nGQ=60} are cached in \pkg{polyCub}, for larger degrees \pkg{statmod} is required.} \item{alpha}{base-line of the (rotated) polygon at \eqn{x = \alpha} (see Sommariva and Vianello (2007) for an explication). If \code{NULL} (default), the midpoint of the x-range of each polygon is chosen if no \code{rotation} is performed, and otherwise the \eqn{x}-coordinate of the rotated point \code{"P"} (see \code{rotation}). If \code{f} has its maximum value at the origin \eqn{(0,0)}, e.g., the bivariate Gaussian density with zero mean, \code{alpha = 0} is a reasonable choice.} \item{rotation}{logical (default: \code{FALSE}) or a list of points \code{"P"} and \code{"Q"} describing the preferred direction. If \code{TRUE}, the polygon is rotated according to the vertices \code{"P"} and \code{"Q"}, which are farthest apart (see Sommariva and Vianello, 2007). For convex polygons, this rotation guarantees that all nodes fall inside the polygon.} \item{engine}{character string specifying the implementation to use. Up to \pkg{polyCub} version 0.4-3, the two-dimensional nodes and weights were computed by \R functions and these are still available by setting \code{engine = "R"}. The new C-implementation is now the default (\code{engine = "C"}) and requires approximately 30\% less computation time.\cr The special setting \code{engine = "C+reduce"} will discard redundant nodes at (0,0) with zero weight resulting from edges on the base-line \eqn{x = \alpha} or orthogonal to it. This extra cleaning is only worth its cost for computationally intensive functions \code{f} over polygons which really have some edges on the baseline or parallel to the x-axis. Note that the old \R implementation does not have such unset zero nodes and weights.} \item{plot}{logical indicating if an illustrative plot of the numerical integration should be produced.} } \value{ The approximated value of the integral of \code{f} over \code{polyregion}.\cr In the case \code{f = NULL}, only the computed nodes and weights are returned in a list of length the number of polygons of \code{polyregion}, where each component is a list with \code{nodes} (a numeric matrix with two columns), \code{weights} (a numeric vector of length \code{nrow(nodes)}), the rotation \code{angle}, and \code{alpha}. } \description{ Product Gauss cubature over polygons as proposed by Sommariva and Vianello (2007). } \examples{ # see example(polyCub) } \author{ Sebastian Meyer\cr The product Gauss cubature is based on the original \acronym{MATLAB} implementation \code{polygauss} by Sommariva and Vianello (2007), which is available under the GNU GPL (>=2) license from \url{http://www.math.unipd.it/~alvise/software.html}. } \references{ Sommariva, A. and Vianello, M. (2007). Product Gauss cubature over polygons based on Green's integration formula. \emph{Bit Numerical Mathematics}, \bold{47} (2), 441-453. } \seealso{ Other polyCub.methods: \code{\link{.polyCub.iso}}, \code{\link{polyCub.iso}}; \code{\link{polyCub.exact.Gauss}}; \code{\link{polyCub.midpoint}}; \code{\link{polyCub}} } \keyword{math} \keyword{spatial} polyCub/man/isScalar.Rd0000644000176000001440000000045612411522266014530 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{isScalar} \alias{isScalar} \title{Checks if Argument is Scalar} \usage{ isScalar(x) } \arguments{ \item{x}{any object} } \value{ logical } \description{ Check if the argument is scalar, i.e. a numeric vector of length 1. } \keyword{internal} polyCub/man/coerce-sp-methods.Rd0000644000176000001440000000125412411522266016305 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{coerce-sp-methods} \alias{coerce,Polygon,Polygons-method} \alias{coerce,Polygon,owin-method} \alias{coerce,Polygons,owin-method} \alias{coerce,SpatialPolygons,owin-method} \alias{coerce-sp-methods} \title{Coerce \code{"Polygons"} to \code{"owin"}} \description{ Package \pkg{polyCub} also implements \code{coerce}-methods (\code{as(object, Class)}) to convert \code{"\link[sp:Polygons-class]{Polygons}"} (or \code{"\link[sp:SpatialPolygons-class]{SpatialPolygons}"} or \code{"\link[sp:Polygon-class]{Polygon}"}) to \code{"\link[spatstat:owin.object]{owin}"}. } \author{ Sebastian Meyer } \keyword{methods} \keyword{spatial} polyCub/man/isClosed.Rd0000644000176000001440000000062012411522266014525 0ustar ripleyusers% Generated by roxygen2 (4.0.2): do not edit by hand \name{isClosed} \alias{isClosed} \title{Check if Polygon is Closed} \usage{ isClosed(coords) } \arguments{ \item{coords}{numeric coordinate matrix. It is interpreted by \code{\link{xy.coords}}.} } \value{ logical } \description{ Check if the first and last coordinates of a coordinate matrix are identical. } \keyword{internal} \keyword{spatial}