polyCub/0000755000176200001440000000000013427056412011673 5ustar liggesuserspolyCub/inst/0000755000176200001440000000000013427003213012637 5ustar liggesuserspolyCub/inst/CITATION0000644000176200001440000000064213426603244014007 0ustar liggesuserscitHeader("To cite", sQuote("polyCub"), "in publications, please refer to:") bibentry( bibtype = "Article", key = "R:polyCub", author = "Sebastian Meyer", title = "{polyCub}: An {R} package for Integration over Polygons", journal = "Journal of Open Source Software", issn = "2475-9066", year = "2019", volume = "4", number = "34", pages = "1056", doi = "10.21105/joss.01056" ) polyCub/inst/doc/0000755000176200001440000000000013427003213013404 5ustar liggesuserspolyCub/inst/doc/polyCub.R0000644000176200001440000000450413427003207015152 0ustar liggesusers## ------------------------------------------------------------------------ library("polyCub") ## ----example-f----------------------------------------------------------- f <- function (s, sigma = 5) { exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2) } ## ----example-polygon----------------------------------------------------- hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) ## ----example, fig.width = 3, fig.height = 2.5---------------------------- plotpolyf(hexagon, f, xlim = c(-8,8), ylim = c(-8,8)) ## ----product-Gauss, echo = -1, fig.show = "hold"------------------------- par(mar = c(3,3,1,2)) polyCub.SV(hexagon, f, nGQ = 3, plot = TRUE) ## ------------------------------------------------------------------------ nrow(polyCub.SV(hexagon, f = NULL, nGQ = 3)[[1]]$nodes) ## ------------------------------------------------------------------------ polyCub.SVn <- function (polyregion, f, ..., nGQ = 20) { nw <- polyCub.SV(polyregion, f = NULL, ..., nGQ = nGQ) ## nw is a list with one element per polygon of 'polyregion' res <- sapply(nw, function (x) c(result = sum(x$weights * f(x$nodes, ...)), nEval = nrow(x$nodes))) structure(sum(res["result",]), nEval = sum(res["nEval",])) } polyCub.SVn(hexagon, f, nGQ = 3) ## ------------------------------------------------------------------------ for (nGQ in c(1:5, 10, 20)) { result <- polyCub.SVn(hexagon, f, nGQ = nGQ) cat(sprintf("nGQ = %2i: %.12f (n=%i)\n", nGQ, result, attr(result, "nEval"))) } ## ---- message = FALSE---------------------------------------------------- library("spatstat") hexagon.owin <- owin(poly = hexagon) ## ----midpoint, echo = -1, fig.show = "hold"------------------------------ par(mar = c(3,3,1,3), xaxs = "i", yaxs = "i") polyCub.midpoint(hexagon.owin, f, eps = 0.5, plot = TRUE) ## ------------------------------------------------------------------------ intrfr <- function (R, sigma = 5) { (1 - exp(-R^2/2/sigma^2))/2/pi } ## ------------------------------------------------------------------------ polyCub.iso(hexagon, intrfr = intrfr, center = c(0,0)) ## ------------------------------------------------------------------------ gpclibPermit() # accept gpclib license (prohibits commercial use) polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)) polyCub/inst/doc/polyCub.html0000644000176200001440000025461013427003213015717 0ustar liggesusers Getting started with polyCub

Getting started with polyCub

Sebastian Meyer

2019-02-07

The R package polyCub implements cubature (numerical integration) over polygonal domains. It solves the problem of integrating a continuously differentiable function f(x,y) over simple closed polygons.

For the special case of a rectangular domain along the axes, the package cubature is more appropriate (cf. CRAN Task View: Numerical Mathematics).

Polygon representations

The integration domain is described by a polygonal boundary (or multiple polygons, including holes). Various R packages for spatial data analysis provide classes for polygons. The implementations differ in vertex order (which direction represents a hole) and if the first vertex is repeated.

All of polyCub’s cubature methods understand

Internally, polyCub uses its auxiliary xylist() function to extract a plain list of lists of vertex coordinates from these classes, such that vertices are ordered anticlockwise and the first vertex is not repeated (i.e., the "owin" convention).

Cubature methods

The following cubature methods are implemented in polyCub:

  1. polyCub.SV(): Product Gauss cubature

  2. polyCub.midpoint(): Two-dimensional midpoint rule

  3. polyCub.iso(): Adaptive cubature for radially symmetric functions \(f(x,y) = f_r(\lVert(x-x_0,y-y_0)\rVert)\)

  4. polyCub.exact.Gauss(): Accurate (but slow) integration of the bivariate Gaussian density

The following section details and illustrates the different cubature methods.

Illustrations

library("polyCub")

We consider the integration of a function f(x,y) which all of the above cubature methods can handle: an isotropic zero-mean Gaussian density. polyCub expects the integrand f to take a two-column coordinate matrix as its first argument (as opposed to separate arguments for the x and y coordinates), so:

f <- function (s, sigma = 5)
{
    exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2)
}

We use a simple hexagon as polygonal integration domain, here specified via an "xylist" of vertex coordinates:

hexagon <- list(
    list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3),
         y = c(-0.5, 4.5, 7, 4.5, -0.5, -3))
)

An image of the function and the integration domain can be produced using polyCub’s rudimentary (but convenient) plotting utility:

plotpolyf(hexagon, f, xlim = c(-8,8), ylim = c(-8,8))

1. Product Gauss cubature: polyCub.SV()

The polyCub package provides an R-interfaced C-translation of “polygauss: Matlab code for Gauss-like cubature over polygons” (Sommariva and Vianello, 2013, http://www.math.unipd.it/~alvise/software.html), an algorithm described in Sommariva and Vianello (2007, BIT Numerical Mathematics, https://doi.org/10.1007/s10543-007-0131-2). The cubature rule is based on Green’s integration formula and incorporates appropriately transformed weights and nodes of one-dimensional Gauss-Legendre quadrature in both dimensions, thus the name “product Gauss cubature”. It is exact for all bivariate polynomials if the number of cubature nodes is sufficiently large (depending on the degree of the polynomial).

For the above example, a reasonable approximation is already obtained with degree nGQ = 3 of the one-dimensional Gauss-Legendre quadrature:

The involved nodes (displayed in the figure above) and weights can be extracted by calling polyCub.SV() with f = NULL, e.g., to determine the number of nodes:

For illustration, we create a variant of polyCub.SV(), which returns the number of function evaluations as an attribute:

We can use this function to investigate how the accuracy of the approximation depends on the degree nGQ and the associated number of cubature nodes:

2. Two-dimensional midpoint rule: polyCub.midpoint()

The two-dimensional midpoint rule in polyCub is a simple wrapper around as.im.function() and integral.im() from package spatstat. In other words, the polygon is represented by a binary pixel image and the integral is approximated as the sum of (pixel area * f(pixel midpoint)) over all pixels whose midpoint is part of the polygon.

To use polyCub.midpoint(), we need to convert our polygon to spatstat’s “owin” class:

Using a pixel size of eps = 0.5 (here yielding 270 pixels), we obtain:

3. Adaptive cubature for isotropic functions: polyCub.iso()

A radially symmetric function can be expressed in terms of the distance r from its point of symmetry: f(r). If the antiderivative of r times f(r), called intrfr(), is analytically available, Green’s theorem leads us to a cubature rule which only needs one-dimensional numerical integration. More specifically, intrfr() will be integrate()d along the edges of the polygon. The mathematical details are given in Meyer and Held (2014, The Annals of Applied Statistics, https://doi.org/10.1214/14-AOAS743, Supplement B, Section 2.4).

For the bivariate Gaussian density f defined above, the integral from 0 to R of r*f(r) is analytically available as:

With this information, we can apply the cubature rule as follows:

Note that we do not even need the original function f.

If intrfr() is missing, it can be approximated numerically using integrate() for r*f(r) as well, but the overall integration will then be much less efficient than product Gauss cubature.

Package polyCub exposes a C-version of polyCub.iso() for use by other R packages (notably surveillance) via LinkingTo: polyCub and #include <polyCubAPI.h>. This requires the intrfr() function to be implemented in C as well. See https://github.com/bastistician/polyCub/blob/master/tests/testthat/polyiso_powerlaw.c for an example.

4. Integration of the bivariate Gaussian density: polyCub.exact.Gauss()

Abramowitz and Stegun (1972, Section 26.9, Example 9) offer a formula for the integral of the bivariate Gaussian density over a triangle with one vertex at the origin. This formula can be used after triangulation of the polygonal domain (polyCub currently uses tristrip() from the gpclib package). The core of the formula is an integral of the bivariate Gaussian density with zero mean, unit variance and some correlation over an infinite rectangle [h, Inf] x [0, Inf], which can be computed accurately using pmvnorm() from the mvtnorm package.

For the above example, we obtain:

The required triangulation as well as the numerous calls of pmvnorm() make this integration algorithm quiet cumbersome. For large-scale integration tasks, it is thus advisable to resort to the general-purpose product Gauss cubature rule polyCub.SV().

Note: polyCub provides an auxiliary function circleCub.Gauss() to calculate the integral of an isotropic Gaussian density over a circular domain (which requires nothing more than a single call of pchisq()).

Benchmark

We use the last result from polyCub.exact.Gauss() as a reference value and tune the number of cubature nodes in polyCub.SV() and polyCub.midpoint() until the absolute error is below 10^-8. This leads to nGQ = 4 for product Gauss cubature and a 1200 x 1200 pixel image for the midpoint rule. For polyCub.iso(), we keep the default tolerance levels of integrate(). For comparison, we also run polyCub.iso() without the analytically derived intrfr function, which leads to a double-integrate approximation.

The median runtimes [ms] of the different cubature methods are given below.

benchmark <- microbenchmark::microbenchmark(
  SV = polyCub.SV(hexagon.owin, f, nGQ = 4),
  midpoint = polyCub.midpoint(hexagon.owin, f, dimyx = 1200),
  iso = polyCub.iso(hexagon.owin, intrfr = intrfr, center = c(0,0)),
  iso_double_approx = polyCub.iso(hexagon.owin, f, center = c(0,0)),
  exact = polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)),
  times = 6,
  check = function (values) all(abs(unlist(values) - 0.274144773813434) < 1e-8))
summary(benchmark, unit = "ms")[c("expr", "median")]
expr median
SV 0.13
midpoint 312.72
iso 0.32
iso_double_approx 4.76
exact 7.81

The general-purpose SV-method is the clear winner of this small competition. A disadvantage of that method is that the number of cubature nodes needs to be tuned manually. This also holds for the midpoint rule, which is by far the slowest option. In contrast, the “iso”-method for radially symmetric functions is based on R’s integrate() function, which implements automatic tolerance levels. Furthermore, the “iso”-method can also be used with “spiky” integrands, such as a heavy-tailed power-law kernel \(f(r) = (r+1)^{-2}\).

polyCub/inst/doc/polyCub.Rmd0000644000176200001440000002557313426777177015533 0ustar liggesusers--- title: "Getting started with polyCub" author: "Sebastian Meyer" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with polyCub} %\VignetteEngine{knitr::rmarkdown} --- ```{R setup, include = FALSE, purl = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` The R package **polyCub** implements *cubature* (numerical integration) over *polygonal* domains. It solves the problem of integrating a continuously differentiable function f(x,y) over simple closed polygons. For the special case of a rectangular domain along the axes, the package [**cubature**](https://CRAN.R-project.org/package=cubature) is more appropriate (cf. [`CRAN Task View: Numerical Mathematics`](https://CRAN.R-project.org/view=NumericalMathematics)). ## Polygon representations The integration domain is described by a polygonal boundary (or multiple polygons, including holes). Various R packages for spatial data analysis provide classes for polygons. The implementations differ in vertex order (which direction represents a hole) and if the first vertex is repeated. All of **polyCub**'s cubature methods understand * `"owin"` from package [**spatstat**](https://CRAN.R-project.org/package=spatstat), * `"gpc.poly"` from [**rgeos**](https://CRAN.R-project.org/package=rgeos) (or [**gpclib**](https://CRAN.R-project.org/package=gpclib)), and * `"SpatialPolygons"` from package [**sp**](https://CRAN.R-project.org/package=sp). Internally, **polyCub** uses its auxiliary `xylist()` function to extract a plain list of lists of vertex coordinates from these classes, such that vertices are ordered anticlockwise and the first vertex is not repeated (i.e., the `"owin"` convention). ## Cubature methods The following cubature methods are implemented in **polyCub**: 1. `polyCub.SV()`: Product Gauss cubature 2. `polyCub.midpoint()`: Two-dimensional midpoint rule 3. `polyCub.iso()`: Adaptive cubature for radially symmetric functions $f(x,y) = f_r(\lVert(x-x_0,y-y_0)\rVert)$ 4. `polyCub.exact.Gauss()`: Accurate (but slow) integration of the bivariate Gaussian density The following section details and illustrates the different cubature methods. ## Illustrations ```{R} library("polyCub") ``` We consider the integration of a function f(x,y) which all of the above cubature methods can handle: an isotropic zero-mean Gaussian density. **polyCub** expects the integrand f to take a two-column coordinate matrix as its first argument (as opposed to separate arguments for the x and y coordinates), so: ```{R example-f} f <- function (s, sigma = 5) { exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2) } ``` We use a simple hexagon as polygonal integration domain, here specified via an `"xylist"` of vertex coordinates: ```{R example-polygon} hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) ``` An image of the function and the integration domain can be produced using **polyCub**'s rudimentary (but convenient) plotting utility: ```{R example, fig.width = 3, fig.height = 2.5} plotpolyf(hexagon, f, xlim = c(-8,8), ylim = c(-8,8)) ``` ### 1. Product Gauss cubature: `polyCub.SV()` The **polyCub** package provides an R-interfaced C-translation of "polygauss: Matlab code for Gauss-like cubature over polygons" (Sommariva and Vianello, 2013, ), an algorithm described in Sommariva and Vianello (2007, *BIT Numerical Mathematics*, ). The cubature rule is based on Green's integration formula and incorporates appropriately transformed weights and nodes of one-dimensional Gauss-Legendre quadrature in both dimensions, thus the name "product Gauss cubature". It is exact for all bivariate polynomials if the number of cubature nodes is sufficiently large (depending on the degree of the polynomial). For the above example, a reasonable approximation is already obtained with degree `nGQ = 3` of the one-dimensional Gauss-Legendre quadrature: ```{R product-Gauss, echo = -1, fig.show = "hold"} par(mar = c(3,3,1,2)) polyCub.SV(hexagon, f, nGQ = 3, plot = TRUE) ``` The involved nodes (displayed in the figure above) and weights can be extracted by calling `polyCub.SV()` with `f = NULL`, e.g., to determine the number of nodes: ```{R} nrow(polyCub.SV(hexagon, f = NULL, nGQ = 3)[[1]]$nodes) ``` For illustration, we create a variant of `polyCub.SV()`, which returns the number of function evaluations as an attribute: ```{R} polyCub.SVn <- function (polyregion, f, ..., nGQ = 20) { nw <- polyCub.SV(polyregion, f = NULL, ..., nGQ = nGQ) ## nw is a list with one element per polygon of 'polyregion' res <- sapply(nw, function (x) c(result = sum(x$weights * f(x$nodes, ...)), nEval = nrow(x$nodes))) structure(sum(res["result",]), nEval = sum(res["nEval",])) } polyCub.SVn(hexagon, f, nGQ = 3) ``` We can use this function to investigate how the accuracy of the approximation depends on the degree `nGQ` and the associated number of cubature nodes: ```{R} for (nGQ in c(1:5, 10, 20)) { result <- polyCub.SVn(hexagon, f, nGQ = nGQ) cat(sprintf("nGQ = %2i: %.12f (n=%i)\n", nGQ, result, attr(result, "nEval"))) } ``` ### 2. Two-dimensional midpoint rule: `polyCub.midpoint()` The two-dimensional midpoint rule in **polyCub** is a simple wrapper around `as.im.function()` and `integral.im()` from package **spatstat**. In other words, the polygon is represented by a binary pixel image and the integral is approximated as the sum of (pixel area * f(pixel midpoint)) over all pixels whose midpoint is part of the polygon. To use `polyCub.midpoint()`, we need to convert our polygon to **spatstat**'s "owin" class: ```{R, message = FALSE} library("spatstat") hexagon.owin <- owin(poly = hexagon) ``` Using a pixel size of `eps = 0.5` (here yielding 270 pixels), we obtain: ```{R midpoint, echo = -1, fig.show = "hold"} par(mar = c(3,3,1,3), xaxs = "i", yaxs = "i") polyCub.midpoint(hexagon.owin, f, eps = 0.5, plot = TRUE) ``` ### 3. Adaptive cubature for *isotropic* functions: `polyCub.iso()` A radially symmetric function can be expressed in terms of the distance r from its point of symmetry: f(r). If the antiderivative of r times f(r), called `intrfr()`, is analytically available, Green's theorem leads us to a cubature rule which only needs *one-dimensional* numerical integration. More specifically, `intrfr()` will be `integrate()`d along the edges of the polygon. The mathematical details are given in Meyer and Held (2014, *The Annals of Applied Statistics*, , Supplement B, Section 2.4). For the bivariate Gaussian density `f` defined above, the integral from 0 to R of `r*f(r)` is analytically available as: ```{R} intrfr <- function (R, sigma = 5) { (1 - exp(-R^2/2/sigma^2))/2/pi } ``` With this information, we can apply the cubature rule as follows: ```{R} polyCub.iso(hexagon, intrfr = intrfr, center = c(0,0)) ``` Note that we do not even need the original function `f`. If `intrfr()` is missing, it can be approximated numerically using `integrate()` for `r*f(r)` as well, but the overall integration will then be much less efficient than product Gauss cubature. Package **polyCub** exposes a C-version of `polyCub.iso()` for use by other R packages (notably [**surveillance**](https://CRAN.R-project.org/package=surveillance)) via `LinkingTo: polyCub` and `#include `. This requires the `intrfr()` function to be implemented in C as well. See for an example. ### 4. Integration of the *bivariate Gaussian density*: `polyCub.exact.Gauss()` Abramowitz and Stegun (1972, Section 26.9, Example 9) offer a formula for the integral of the bivariate Gaussian density over a triangle with one vertex at the origin. This formula can be used after triangulation of the polygonal domain (**polyCub** currently uses `tristrip()` from the [**gpclib**](https://CRAN.R-project.org/package=gpclib) package). The core of the formula is an integral of the bivariate Gaussian density with zero mean, unit variance and some correlation over an infinite rectangle [h, Inf] x [0, Inf], which can be computed accurately using `pmvnorm()` from the [**mvtnorm**](https://CRAN.R-project.org/package=mvtnorm) package. For the above example, we obtain: ```{R} gpclibPermit() # accept gpclib license (prohibits commercial use) polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)) ``` The required triangulation as well as the numerous calls of `pmvnorm()` make this integration algorithm quiet cumbersome. For large-scale integration tasks, it is thus advisable to resort to the general-purpose product Gauss cubature rule `polyCub.SV()`. Note: **polyCub** provides an auxiliary function `circleCub.Gauss()` to calculate the integral of an *isotropic* Gaussian density over a *circular* domain (which requires nothing more than a single call of `pchisq()`). ## Benchmark We use the last result from `polyCub.exact.Gauss()` as a reference value and tune the number of cubature nodes in `polyCub.SV()` and `polyCub.midpoint()` until the absolute error is below 10^-8. This leads to `nGQ = 4` for product Gauss cubature and a 1200 x 1200 pixel image for the midpoint rule. For `polyCub.iso()`, we keep the default tolerance levels of `integrate()`. For comparison, we also run `polyCub.iso()` without the analytically derived `intrfr` function, which leads to a double-`integrate` approximation. The median runtimes [ms] of the different cubature methods are given below. ```{r benchmark, purl = FALSE, eval = identical(Sys.getenv("NOT_CRAN"), "true")} benchmark <- microbenchmark::microbenchmark( SV = polyCub.SV(hexagon.owin, f, nGQ = 4), midpoint = polyCub.midpoint(hexagon.owin, f, dimyx = 1200), iso = polyCub.iso(hexagon.owin, intrfr = intrfr, center = c(0,0)), iso_double_approx = polyCub.iso(hexagon.owin, f, center = c(0,0)), exact = polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)), times = 6, check = function (values) all(abs(unlist(values) - 0.274144773813434) < 1e-8)) ``` ```{r, purl = FALSE, eval = FALSE} summary(benchmark, unit = "ms")[c("expr", "median")] ``` ```{r, purl = FALSE, echo = FALSE, eval = identical(Sys.getenv("NOT_CRAN"), "true")} knitr::kable(summary(benchmark, unit = "ms")[c("expr", "median")], digits = 2) ``` The general-purpose SV-method is the clear winner of this small competition. A disadvantage of that method is that the number of cubature nodes needs to be tuned manually. This also holds for the midpoint rule, which is by far the slowest option. In contrast, the "iso"-method for radially symmetric functions is based on R's `integrate()` function, which implements automatic tolerance levels. Furthermore, the "iso"-method can also be used with "spiky" integrands, such as a heavy-tailed power-law kernel $f(r) = (r+1)^{-2}$. polyCub/inst/include/0000755000176200001440000000000013163463332014273 5ustar liggesuserspolyCub/inst/include/polyCubAPI.h0000644000176200001440000000325713163463332016422 0ustar liggesusers/******************************************************************************* * Header file with wrapper functions for the C-routines provided by polyCub * * Copyright (C) 2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ #include // NULL #include // SEXP #include // R_GetCCallable typedef double (*intrfr_fn) (double, double*); void polyCub_iso( double *x, double *y, // vertex coordinates (open) int *L, // number of vertices intrfr_fn intrfr, // F(R) double *pars, // parameters for F(R) double *center_x, double *center_y, // center of isotropy int *subdivisions, double *epsabs, double *epsrel, // Rdqags options int *stop_on_error, // !=0 means to stop at first ier > 0 double *value, double *abserr, int *neval) // results { static void(*fun)(double*,double*,int*,intrfr_fn,double*,double*,double*, int*,double*,double*,int*,double*,double*,int*) = NULL; if (fun == NULL) fun = (void(*)(double*,double*,int*,intrfr_fn,double*,double*,double*, int*,double*,double*,int*,double*,double*,int*)) R_GetCCallable("polyCub", "polyiso"); fun(x, y, L, intrfr, pars, center_x, center_y, subdivisions, epsabs, epsrel, stop_on_error, value, abserr, neval); return; } polyCub/tests/0000755000176200001440000000000013357377573013055 5ustar liggesuserspolyCub/tests/testthat/0000755000176200001440000000000013357377573014715 5ustar liggesuserspolyCub/tests/testthat/polyiso_powerlaw.c0000644000176200001440000000344713163463332020467 0ustar liggesusers/******************************************************************************* * Example of using the C-routine "polyCub_iso", see also test-polyiso.R * * Copyright (C) 2015,2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ #include #include // F(R) example static double intrfr_powerlaw(double R, double *logpars) { double sigma = exp(logpars[0]); double d = exp(logpars[1]); if (d == 1.0) { return R - sigma * log(R/sigma + 1); } else if (d == 2.0) { return log(R/sigma + 1) - R/(R+sigma); } else { return (R*pow(R+sigma,1-d) - (pow(R+sigma,2-d) - pow(sigma,2-d))/(2-d)) / (1-d); } } // function to be called from R void C_polyiso_powerlaw( double *x, double *y, // vertex coordinates (open) int *L, // number of vertices //intrfr_fn intrfr, // F(R) double *pars, // parameters for F(R) double *center_x, double *center_y, // center of isotropy int *subdivisions, double *epsabs, double *epsrel, // Rdqags options int *stop_on_error, // !=0 means to stop at first ier > 0 double *value, double *abserr, int *neval) // results { polyCub_iso(x, y, L, intrfr_powerlaw, pars, center_x, center_y, subdivisions, epsabs, epsrel, stop_on_error, value, abserr, neval); return; } polyCub/tests/testthat/test-NWGL.R0000644000176200001440000000167413357377573016574 0ustar liggesuserscontext("Validation of cached Gauss-Legendre nodes/weights") test_that("statmod::gauss.quad() still gives the same result", { new.NWGL <- lapply( X = seq_len(61L), FUN = function (n) unname(statmod::gauss.quad(n = n, kind = "legendre")) ) expect_equal(new.NWGL, .NWGL, check.attributes = FALSE) }) test_that("polyCub.SV() can fetch nodes and weights from 'statmod'", { diamond <- list(list(x = c(1,2,1,0), y = c(1,2,3,2))) nw <- polyCub.SV(diamond, f = NULL, nGQ = 83) expect_is(nw, "list") }) test_that("polyCub.SV() can reduce nodes with zero weight", { rectangle <- list(list(x = c(-1,1,1,-1), y = c(1,1,2,2))) ##nw0 <- polyCub.SV(rectangle, f = NULL, nGQ = 3, engine = "C")[[1]] # 0s nw <- polyCub.SV(rectangle, f = NULL, nGQ = 3, engine = "C+reduce")[[1]] expect_true(all(nw$weights != 0)) ##f <- function (s) 1 # => calculate area (= 2) expect_equal(sum(nw$weights), 2) }) polyCub/tests/testthat/test-regression.R0000644000176200001440000000116313165175161020160 0ustar liggesuserscontext("Regression tests") hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) f <- function (s) (rowSums(s^2)+1)^-2 ##plotpolyf(hexagon, f) test_that("isotropic cubature can handle control list for integrate()", { ## previosly, passing control arguments did not work int1 <- polyCub.iso(hexagon, f, center=c(0,0), control=list(rel.tol=1e-3)) int2 <- polyCub.iso(hexagon, f, center=c(0,0), control=list(rel.tol=1e-8)) ## results are almost but not identical expect_equal(int1, int2, tolerance = 1e-3) expect_false(identical(int1, int2)) }) polyCub/tests/testthat/test-polyCub.R0000644000176200001440000000441513357136712017422 0ustar liggesuserscontext("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 ## target value of the integral over the _polygonal_ circle intExact <- 0.65844436 ## taken from exact.Gauss cubature test_that("gpclibCheck() fails without prior license agreement", { if (gpclibPermitStatus()) skip("gpclib license has already been accepted") expect_error(polyCub:::gpclibCheck()) }) 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_equal(int, 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_equal(intExact, 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_equal(int, 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_equal(intC, intR) expect_equal(intC, 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_equal(int0, intExact, check.attributes=FALSE) }) polyCub/tests/testthat/test-polyiso.R0000644000176200001440000001013513357131525017474 0ustar liggesuserscontext("polyCub_iso C-routine (API)") ## CAVE (as of R-3.4.0 with testthat 1.0.2): ## During R CMD check, tools:::.runPackageTests() sets R_TESTS=startup.Rs, ## a file which is created in the parent directory "tests", see ## file.path(R.home("share"), "R", "tests-startup.R") ## for its contents. However, testthat tests are run with the working directory ## set to here, so auxiliary R sessions initiated here would fail when trying ## to source() the R_TESTS file on startup, see the system Rprofile file ## file.path(R.home("library"), "base", "R", "Rprofile") ## for what happens. Solution: unset R_TESTS (or set to "") for sub-R processes. ## function to call an R CMD with environment variables ## 'env' specified as a named character vector Rcmd <- function (args, env = character(), ...) { stopifnot(is.vector(env, mode = "character"), !is.null(names(env))) if (.Platform$OS.type == "windows") { if (length(env)) { ## the 'env' argument of system2() is not supported on Windows setenv <- function (envs) { old <- Sys.getenv(names(envs), unset = NA, names = TRUE) set <- !is.na(envs) if (any(set)) do.call(Sys.setenv, as.list(envs[set])) if (any(!set)) Sys.unsetenv(names(envs)[!set]) invisible(old) } oldenv <- setenv(env) on.exit(setenv(oldenv)) } system2(command = file.path(R.home("bin"), "Rcmd.exe"), args = args, ...) } else { system2(command = file.path(R.home("bin"), "R"), args = c("CMD", args), env = paste(names(env), env, sep = "="), ...) } } message("compiling polyiso_powerlaw.c using R CMD SHLIB") shlib_error <- Rcmd( args = c("SHLIB", "--clean", "polyiso_powerlaw.c"), env = c("PKG_CPPFLAGS" = paste0( "-I", system.file("include", package="polyCub") ), "R_TESTS" = "") ) if (shlib_error) skip("failed to build the shared object/DLL for the polyCub_iso example") ## load shared object/DLL myDLL <- paste0("polyiso_powerlaw", .Platform$dynlib.ext) loadNamespace("polyCub") dyn.load(myDLL) ## R function calling C_polyiso_powerlaw polyiso_powerlaw <- function (xypoly, logpars, center, subdivisions = 100L, rel.tol = .Machine$double.eps^0.25, abs.tol = rel.tol, stop.on.error = TRUE) { .C("C_polyiso_powerlaw", as.double(xypoly$x), as.double(xypoly$y), as.integer(length(xypoly$x)), as.double(logpars), as.double(center[1L]), as.double(center[2L]), as.integer(subdivisions), as.double(abs.tol), as.double(rel.tol), as.integer(stop.on.error), value = double(1L), abserr = double(1L), neval = integer(1L) )[c("value", "abserr", "neval")] } ## example polygon and function parameters diamond <- list(x = c(1,2,1,0), y = c(1,2,3,2)) logpars <- log(c(0.5, 1)) center <- c(0.5,2.5) # lies on an edge (to cover that case as well) (res <- polyiso_powerlaw(xypoly = diamond, logpars = logpars, center = center)) ## compare with R implementation intrfr.powerlaw <- function (R, logpars) { sigma <- exp(logpars[[1L]]) d <- exp(logpars[[2L]]) if (d == 1) { R - sigma * log(R/sigma + 1) } else if (d == 2) { log(R/sigma + 1) - R/(R+sigma) } else { (R*(R+sigma)^(1-d) - ((R+sigma)^(2-d) - sigma^(2-d))/(2-d)) / (1-d) } } (orig <- polyCub:::polyCub1.iso(poly = diamond, intrfr = intrfr.powerlaw, logpars = logpars, center = center)) test_that("C and R implementations give equal results", { expect_equal(res$value, orig[1L]) expect_equal(res$abserr, orig[2L]) }) ## microbenchmark::microbenchmark( ## polyCub:::polyCub1.iso(diamond, intrfr.powerlaw, logpars, center=center), ## polyiso_powerlaw(diamond, logpars, center=center), ## times = 1000) ## ## 140 mus vs. 35 mus dyn.unload(myDLL) file.remove(myDLL) polyCub/tests/test-all.R0000644000176200001440000000013613111116012014664 0ustar liggesusersif (require("testthat") && packageVersion("testthat") >= "0.9") { test_check("polyCub") } polyCub/src/0000755000176200001440000000000013427003213012451 5ustar liggesuserspolyCub/src/polyCub.SV.h0000644000176200001440000000160113427003213014564 0ustar liggesusers/******************************************************************************* * Header file of polyCub.SV.c * * Copyright (C) 2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ 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); polyCub/src/polyCub.SV.c0000644000176200001440000000571613427003213014572 0ustar liggesusers/******************************************************************************* * C-version of .polygauss.side() * * Copyright (C) 2014,2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ #include "polyCub.SV.h" static 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/src/polyCub.iso.h0000644000176200001440000000176713427003213015043 0ustar liggesusers/******************************************************************************* * Header file of polyCub.iso.c * * Copyright (C) 2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ typedef double (*intrfr_fn) (double, double*); void polyiso( double *x, double *y, // vertex coordinates (open) int *L, // number of vertices intrfr_fn intrfr, // F(R) double *pars, // parameters for F(R) double *center_x, double *center_y, // center of isotropy int *subdivisions, double *epsabs, double *epsrel, // Rdqags options int *stop_on_error, // !=0 means to stop at first ier > 0 double *value, double *abserr, int *neval); // results polyCub/src/polyCub.iso.c0000644000176200001440000001171413427003213015027 0ustar liggesusers/******************************************************************************* * C-version of polyCub1.iso() * * Copyright (C) 2015,2017 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ /* The corresponding math is derived in Supplement B (Section 2.4) of * Meyer and Held (2014): "Power-law models for infectious disease spread." * The Annals of Applied Statistics, 8(3), 1612-1639. * https://doi.org/10.1214/14-AOAS743SUPPB */ #include // R_FINITE, otherwise math.h would suffice #include // error #include // R_alloc #include // Rprintf #include // Rdqags // header file defines the intrfr_fn type #include "polyCub.iso.h" // integrand for the edge (x0,y0) -> (x1,y1), see Equation 7 static double lineIntegrand( double t, double x0, double y0, double x1, double y1, intrfr_fn intrfr, double *pars) { double num = y1*x0 - x1*y0; // numerator term // point on the edge corresponding to t double px = x0 + t*(x1-x0); double py = y0 + t*(y1-y0); double norm2 = px*px + py*py; // evaluate F(R) = int_0^R r*f(r) dr at R=||(px,py)|| double inti = intrfr(sqrt(norm2), pars); if (!R_FINITE(inti)) error("non-finite intrfr value at R=%f", sqrt(norm2)); return num*inti/norm2; } // set of parameters for line integration (passed via the *ex argument) typedef struct { double x0, y0, x1, y1; intrfr_fn intrfr; double *pars; } Params; // vectorized lineIntegrand for use with Rdqags static void myintegr_fn(double *x, int n, void *ex) { Params *param = (Params *) ex; for(int i = 0; i < n; i++) { x[i] = lineIntegrand(x[i], param->x0, param->y0, param->x1, param->y1, param->intrfr, param->pars); } return; } // calculate line integral for one edge (x0,y0) -> (x1,y1) // using Gauss-Kronrod quadrature via Rdqags as declared in , // implemented in R/src/appl/integrate.c, // and used in R/src/library/stats/src/integrate.c static void polyiso_side( double x0, double y0, double x1, double y1, // 2 vertices intrfr_fn intrfr, double *pars, // F(R) int subdivisions, double *epsabs, double *epsrel, // control double *result, double *abserr, int *neval, int *ier) // results { double num = y1*x0 - x1*y0; // numerator in lineIntegrand // for any point p on the edge if (num == 0.0) { // 'center' is part of this polygon edge *result = 0.0; *abserr = 0.0; //*last = 0; *neval = 0; *ier = 0; return; } // set of parameters for lineIntegrand Params param = {x0, y0, x1, y1, intrfr, pars}; // prepare for Rdqags double lower = 0.0; double upper = 1.0; int lenw = 4 * subdivisions; int last; // unused int *iwork = (int *) R_alloc((size_t) subdivisions, sizeof(int)); double *work = (double *) R_alloc((size_t) lenw, sizeof(double)); Rdqags(myintegr_fn, ¶m, &lower, &upper, epsabs, epsrel, result, abserr, neval, ier, // results &subdivisions, &lenw, &last, iwork, work); return; } // line integration along the edges of a polygon void polyiso( double *x, double *y, // vertex coordinates (open) int *L, // number of vertices intrfr_fn intrfr, // F(R) double *pars, // parameters for F(R) double *center_x, double *center_y, // center of isotropy int *subdivisions, double *epsabs, double *epsrel, // Rdqags options int *stop_on_error, // !=0 means to stop at first ier > 0 double *value, double *abserr, int *neval) // results { // auxiliary variables double resulti, abserri; int nevali, ieri; double x0, y0, x1, y1; int idxTo; // initialize result at 0 (do += for each polygon edge); *value = 0.0; *abserr = 0.0; *neval = 0; for (int i = 0; i < *L; i++) { x0 = x[i] - *center_x; y0 = y[i] - *center_y; idxTo = (i == *L-1) ? 0 : i+1; x1 = x[idxTo] - *center_x; y1 = y[idxTo] - *center_y; polyiso_side(x0, y0, x1, y1, intrfr, pars, *subdivisions, epsabs, epsrel, &resulti, &abserri, &nevali, &ieri); if (ieri > 0) { if (*stop_on_error == 0) { Rprintf("abnormal termination of integration routine (%i)\n", ieri); } else { error("abnormal termination of integration routine (%i)\n", ieri); } } *value += resulti; *abserr += abserri; *neval += nevali; } return; } polyCub/src/init.c0000644000176200001440000000236213427003213013563 0ustar liggesusers/******************************************************************************* * Registering native routines (entry points in compiled code) * * Copyright (C) 2017,2019 Sebastian Meyer * * This file is 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 https://www.R-project.org/Licenses/. ******************************************************************************/ #include // for NULL #include // for SEXP types #include #include "polyCub.SV.h" #include "polyCub.iso.h" // types array (could be omitted) static R_NativePrimitiveArgType C_polygauss_t[] = { REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, /*L, M, N:*/ INTSXP, INTSXP, INTSXP, /*results:*/ REALSXP, REALSXP, REALSXP }; static const R_CMethodDef CEntries[] = { {"C_polygauss", (DL_FUNC) &C_polygauss, 13, C_polygauss_t}, {NULL, NULL, 0, NULL} }; void R_init_polyCub(DllInfo *dll) { R_registerRoutines(dll, CEntries, NULL, NULL, NULL); R_useDynamicSymbols(dll, FALSE); //R_forceSymbols(dll, TRUE); // would require R >= 3.0.0 R_RegisterCCallable("polyCub", "polyiso", (DL_FUNC) &polyiso); } polyCub/NAMESPACE0000644000176200001440000000302413357664114013117 0ustar liggesusers# Generated by roxygen2: 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(as.owin.Polygon) export(as.owin.Polygons) export(as.owin.SpatialPolygons) export(as.owin.gpc.poly) 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) if(getRversion() >= "3.6.0") { # delayed registration S3method(spatstat::as.owin, SpatialPolygons) S3method(spatstat::as.owin, Polygons) S3method(spatstat::as.owin, Polygon) } if(getRversion() >= "3.6.0") { # delayed registration S3method(spatstat::as.owin, gpc.poly) } import(methods) importClassesFrom(sp,Polygon) importClassesFrom(sp,Polygons) importClassesFrom(sp,SpatialPolygons) importClassesFrom(sp,owin) importFrom(grDevices,extendrange) importFrom(grDevices,gray) importFrom(grDevices,heat.colors) importFrom(grDevices,xy.coords) importFrom(graphics,image) importFrom(graphics,lines) importFrom(graphics,points) importFrom(graphics,polygon) importFrom(sp,Polygons) importFrom(sp,SpatialPolygons) importFrom(sp,coordinates) importFrom(sp,plot) importFrom(stats,cov2cor) importFrom(stats,dist) importFrom(stats,integrate) importFrom(stats,pchisq) importFrom(stats,pnorm) useDynLib(polyCub, .registration = TRUE) polyCub/NEWS.md0000644000176200001440000001732713426776565013024 0ustar liggesuserspolyCub 0.7.1 (2019-02-07) ========================== * Added a *getting started* `vignette("polyCub")` (suggested by @wrathematics in [openjournals/joss-reviews#1056](https://github.com/openjournals/joss-reviews/issues/1056)). * fix minor compiler warning about missing `types` field in `R_CMethodDef` (@wrathematics, [#1](https://github.com/bastistician/polyCub/issues/1)). polyCub 0.7.0 (2018-10-11) ========================== * Package **polyCub** no longer attaches package [**sp**](https://CRAN.R-project.org/package=sp) (moved from "Depends" to "Imports"). * The R code of the examples is no longer installed by default. Use the `--example` flag of R CMD INSTALL to achieve that. * The README now exemplifies the four different cubature rules. polyCub 0.6.1 (2017-10-02) ========================== * The exported C-function `polyCub_iso()` ... * did not handle its `stop_on_error` argument correctly (it would always stop on error). * now detects non-finite `intrfr` function values and gives an informative error message (rather than just reporting "abnormal termination of integration routine"). * Package **polyCub** no longer strictly depends on package [**spatstat**](https://CRAN.R-project.org/package=spatstat). It is only required for `polyCub.midpoint()` and for polygon input of class `"owin"`. polyCub 0.6.0 (2017-05-24) ========================== * Added full C-implementation of `polyCub.iso()`, which is exposed as `"polyCub_iso"` for use by other R packages (notably future versions of [**surveillance**](https://CRAN.R-project.org/package=surveillance)) via `LinkingTo: polyCub` and `#include `. * Accommodate CRAN checks: add missing import from **graphics**, register native routines and disable symbol search polyCub 0.5-2 (2015-02-25) ========================== * `polyCub.midpoint()` works directly with input polygons of classes `"gpc.poly"` and `"SpatialPolygons"`, since package **polyCub** now registers corresponding `as.owin`-methods. * `polyCub.exact.Gauss()` did not work if the `tristrip` of the transformed input polygon contained degenerate triangles (spotted by Ignacio Quintero). * Line integration in `polyCub.iso()` could break due to division by zero if the `center` point was part of the polygon boundary. polyCub 0.5-1 (2014-10-24) ========================== * Nodes and weights for `polyCub.SV()` were only cached up to `nGQ=59`, not 60 as announced in version 0.5-0. Fixed that which also makes examples truly run without **statmod**. * In `polyCub.SV()`, the new special setting `f=NULL` means to only compute nodes and weights. * Internal changes to the `"gpc.poly"` converters to accommodate [**spatstat**](https://CRAN.R-project.org/package=spatstat) 1.39-0. polyCub 0.5-0 (2014-05-07) ========================== * `polyCub.SV()` gained an argument `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. * Package [**statmod**](https://CRAN.R-project.org/package=statmod) is no longer strictly required (imported). Nodes and weights for Gauss-Legendre quadrature in `polyCub.SV()` are now cached in the **polyCub** package up to `nGQ=60`. **statmod**`::gauss.quad` is only queried for a higher number of nodes. polyCub 0.4-3 (2014-03-14) ========================== * `polyCub.iso()` ... * could not handle additional arguments for `integrate()` given in the `control` list. * now applies the `control` arguments also to the numerical approximation of `intrfr`. * The `checkintrfr()` function is exported and documented. * Added a CITATION file. polyCub 0.4-2 (2014-02-12) ========================== * `plotpolyf()` ... * gained an additional argument `print.args`, an optional list of arguments passed to `print.trellis()` if `use.lattice=TRUE`. * passed a *data frame* of coordinates to `f` instead of a matrix as documented. polyCub 0.4-1 (2013-12-05) ========================== * This version solely fixes a missing NAMESPACE import to make package **polyCub** again compatible with older versions of [**spatstat**](https://CRAN.R-project.org/package=spatstat) (< 1.33-0). polyCub 0.4-0 (2013-11-19) ========================== INFRASTRUCTURE -------------- * [**rgeos**](https://CRAN.R-project.org/package=rgeos) (and therefore the GEOS library) is no longer strictly required (moved from "Imports" to "Suggests"). * Added `coerce`-methods from `"Polygons"` (or `"SpatialPolygons"` or `"Polygon"`) to `"owin"` (`as(..., "owin")`). * S4-style `coerce`-methods between `"gpc.poly"` and `"Polygons"`/`"owin"` have been removed from the package (since we no longer import the formal class `"gpc.poly"` from **gpclib** or **rgeos**). However, there are two new functions `gpc2owin` and `owin2gpc` similar to those dropped from [**spatstat**](https://CRAN.R-project.org/package=spatstat) since version 1.34-0. * Moved `discpoly()` back to [**surveillance**](https://CRAN.R-project.org/package=surveillance) since it is only used there. * The latter two changes cause [**surveillance**](https://CRAN.R-project.org/package=surveillance) version 1.6-0 to be incompatible with this new version of **polyCub**. Appropriate modifications have been made in the new version 1.7-0 of **surveillance**. SPEED-UP `polyCub.SV()` ----------------------- * thorough optimization of `polyCub.SV()`-related code resulted in about 27% speed-up: * use `mapply()` instead of a `for`-loop * avoid `cbind()` * use `tcrossprod()` * less object copying MINOR CHANGES ------------- * `xylist()` is now exported. It simply extracts polygon coordinates from various spatial classes (with same unifying intention as `xy.coords()`). * A `polyregion` of class `"SpatialPolygons"` of length more than 1 now works in `polyCub`-methods. * Use aspect ratio of 1 in `plotpolyf()`. polyCub 0.3-1 (2013-08-22) ========================== * This version solely fixes a few typos and a technical note from `R CMD check` in the current R development version (also import packages into the NAMESPACE which are listed in the "Depends" field). polyCub 0.3-0 (2013-07-06) ========================== * New cubature method `polyCub.iso()` specific to isotropic functions (thanks to Emil Hedevang for the basic idea). * New function `plotpolyf()` to plot a polygonal domain on top of an image of a bivariate function. * The package now depends on R >= 2.15.0 (for `.rowSums()`). * The package no longer registers `"owin"` as an S4-class since we depend on the **sp** package which does the job. This avoids a spurious warning (in `.simpleDuplicateClass()`) upon package installation. * In `discpoly()`, the argument `r` has been renamed to `radius`. This is backward compatible by partial argument matching in old code. polyCub 0.2-0 (2013-05-09) ========================== * This is the initial version of the **polyCub** package mainly built on functions previously maintained within the [**surveillance**](https://CRAN.R-project.org/package=surveillance) package. These methods for cubature of polygonal domains have been outsourced into this separate **polyCub** package since they are of general use for other packages as well. * The **polyCub** package has more documentation and tests, avoids the use of [**gpclib**](https://CRAN.R-project.org/package=gpclib) as far as possible (using [**rgeos**](https://CRAN.R-project.org/package=rgeos) instead), and solves a compatibility issue with package [**maptools**](https://CRAN.R-project.org/package=maptools) (use `setClass("owin")` instead of `setOldClass("owin")`). polyCub/R/0000755000176200001440000000000013424543542012076 5ustar liggesuserspolyCub/R/polyCub.SV.R0000644000176200001440000003412713424543542014174 0ustar liggesusers################################################################################ ### polyCub.SV: Product Gauss Cubature over Polygonal Domains ### ### Copyright (C) 2009-2014,2017-2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' 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-valued function to be integrated over ##' \code{polyregion} (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 ##' These R and C implementations of product Gauss cubature are 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.\cr ##' DOI-Link: \url{https://doi.org/10.1007/s10543-007-0131-2} ##' @keywords math spatial ##' @family polyCub-methods ##' @importFrom graphics points ##' @example examples/setting.R ##' @example examples/polyCub.SV.R ##' @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)}. ##' @inherit polyCub.SV params references ##' @keywords internal ##' @useDynLib polyCub, .registration = TRUE 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) / vecnorm(Q-P) ## determine rotation angle [radian] 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 } ## 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.R0000644000176200001440000002521713357335027014440 0ustar liggesusers################################################################################ ### polyCub.iso: Cubature of Isotropic Functions over Polygonal Domains ### ### Copyright (C) 2013-2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ #' Cubature of Isotropic Functions over Polygonal Domains #' #' \code{polyCub.iso} numerically integrates a radially symmetric 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 approximates a line integral along the polygon boundary using #' \code{\link{integrate}}. The integrand requires the antiderivative of #' \eqn{r f_r(r)}), which should be supplied as argument \code{intrfr} #' (\code{f} itself is only required if \code{check.intrfr=TRUE}). #' The two-dimensional integration problem thereby reduces to an efficient #' adaptive quadrature in one dimension. #' If \code{intrfr} is not available analytically, \code{polyCub.iso} can use a #' numerical approximation (meaning \code{integrate} within \code{integrate}), #' but the general-purpose cubature method \code{\link{polyCub.SV}} might be #' more efficient in this case. #' See Meyer and Held (2014, Supplement B, Section 2.4) for mathematical #' details. #' #' @inheritParams plotpolyf #' @param intrfr a \code{function(R, ...)}, which implements the (analytical) #' antiderivative of \eqn{r f_r(r)} from 0 to \code{R}. The first argument #' must be vectorized but not necessarily named \code{R}.\cr #' If \code{intrfr} is missing, it will be approximated numerically via #' \code{\link{integrate}(function(r, ...) #' r * f(cbind(x0 + r, y0), ...), 0, R, ..., control=control)}, #' where \code{c(x0, y0)} is the \code{center} of isotropy. #' Note that \code{f} will \emph{not} be checked for isotropy. #' @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 #' upper bound 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{https://doi.org/10.1214/14-AOAS743}, #' \href{https://arxiv.org/abs/1308.5115}{arXiv:1308.5115} #' @seealso #' \code{system.file("include", "polyCubAPI.h", package = "polyCub")} #' for a full C-implementation of this cubature method (for a \emph{single} #' polygon). The corresponding C-routine \code{polyCub_iso} can be used by #' other \R packages, notably \pkg{surveillance}, via \samp{LinkingTo: polyCub} #' (in the \file{DESCRIPTION}) and \samp{#include } (in suitable #' \file{/src} files). Note that the \code{intrfr} function must then also be #' supplied as a C-routine. An example can be found in the package tests. #' @keywords math spatial #' @family polyCub-methods #' @example 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 center <- as.vector(center, mode = "numeric") stopifnot(length(center) == 2L, is.finite(center)) ## 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 (default), 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[1L]+r, center[2L], deparse.level=0L), ...) quadrfr1 <- function (R, ...) integrate(rfr, 0, R, ...)$value if (length(control)) body(quadrfr1)[[2L]] <- as.call(c(as.list(body(quadrfr1)[[2L]]), control)) quadrfr <- function (R, ...) vapply(X = R, FUN = quadrfr1, FUN.VALUE = 0, ..., 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) } ##' @description ##' \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 upper bound 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) { res <- sum(vapply(X=ints, FUN="[", FUN.VALUE=0, 1L, USE.NAMES=FALSE)) attr(res, "abs.error") <- sum(vapply(X=ints, FUN="[", FUN.VALUE=0, 2L, USE.NAMES=FALSE)) res } 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=0L) 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") ## } if (.witherror) { c(int, sum(erredges)) } else { int } } ## line integral for one edge ##' @importFrom stats integrate lineInt <- function (v0, v1, intrfr, ..., control = list()) { d <- v1 - v0 num <- v1[2L]*v0[1L] - v1[1L]*v0[2L] # = d[2]*p[,1] - d[1]*p[,2] # for any point p on the edge if (num == 0) { # i.e., if 'center' is part of this polygon edge return(list(value = 0, abs.error = 0)) } integrand <- function (t) { ## get the points on the edge corresponding to t p <- cbind(v0[1L] + t*d[1L], v0[2L] + t*d[2L], deparse.level=0L) norm2 <- .rowSums(p^2, length(t), 2L) 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) } } polyCub/R/polyCub.R0000644000176200001440000000440513424543542013641 0ustar liggesusers################################################################################ ### polyCub: Wrapper Function for the Various Cubature Methods ### ### Copyright (C) 2009-2013,2019 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ #' Wrapper Function for the Various Cubature Methods #' #' The wrapper function \code{polyCub} can be used to call specific cubature #' methods via its \code{method} argument. It calls \code{\link{polyCub.SV}} #' by default, which implements general-purpose product Gauss cubature. #' #' @inheritParams plotpolyf #' @param f a two-dimensional real-valued function to be integrated over #' \code{polyregion}. 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.\cr #' 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 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}. #' @seealso Details and examples in the \code{vignette("polyCub")} #' and on the method-specific help pages. #' @family polyCub-methods #' @keywords math spatial #' @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]] <- call("::", as.name("polyCub"), as.name(paste("polyCub", method, sep="."))) if (method == "exact.Gauss") cl$f <- NULL int <- eval(cl, parent.frame()) int } polyCub/R/sysdata.rda0000644000176200001440000004464412375637762014266 0ustar liggesusers7zXZi"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.R0000644000176200001440000000642213424543542015464 0ustar liggesusers################################################################################ ### polyCub.midpoint: Two-Dimensional Midpoint Rule ### ### Copyright (C) 2009-2015,2017 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ #' 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 a corresponding #' \code{\link[spatstat]{as.owin}}-method. #' Note that this includes polygons of the classes \code{"gpc.poly"} and #' \code{"\linkS4class{SpatialPolygons}"}, because \pkg{polyCub} defines #' methods \code{\link{as.owin.gpc.poly}} and #' \code{\link{as.owin.SpatialPolygons}}, respectively. #' @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 #' @importFrom sp plot #' @importFrom grDevices gray #' @example examples/setting.R #' @example examples/polyCub.midpoint.R #' @export 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( spatstat::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("inapplicable choice of bandwidth (eps=", format(eps), ") in midpoint rule:\n", e) }) ### ILLUSTRATION ### if (plot) { spatstat::plot.im(IM, axes=TRUE, col=gray(31:4/35), main="") ## add evaluation points #with(IM, points(expand.grid(xcol, yrow), 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 spatstat::integral.im(IM) } polyCub/R/xylist.R0000644000176200001440000001102313165117516013552 0ustar liggesusers################################################################################ ### xylist: Convert Various Polygon Classes to a Simple List of Vertices ### ### Copyright (C) 2012-2014,2017 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' 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{"\linkS4class{Polygons}"} from package \pkg{sp} ##' (as well as \code{"\linkS4class{Polygon}"} and ##' \code{"\linkS4class{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 ##' @export xylist.owin <- function (object, ...) { spatstat::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. ##' @importFrom sp coordinates ##' @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.R0000644000176200001440000002010713424543542016022 0ustar liggesusers################################################################################ ### polyCub.exact.Gauss: Quasi-Exact Cubature of the Bivariate Normal Density ### ### Copyright (C) 2009-2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ #' Quasi-Exact Cubature of the Bivariate Normal Density #' #' The bivariate Gaussian density can be integrated based on a triangulation of #' the (transformed) polygonal domain, using 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: \eqn{(AOB+BOC-AOC)} or \eqn{(AOB-AOC-BOC)} or #' \eqn{(AOB+AOC-BOC)} or \eqn{(AOC+BOC-AOB)} or \ldots. #' However, the most time consuming step is the #' evaluation of \code{\link[mvtnorm]{pmvnorm}}. #' #' @note The package \pkg{gpclib} is required to produce the #' \code{tristrip}, since this is not implemented in \pkg{rgeos} #' (as of version 0.3-25). #' The restricted license of \pkg{gpclib} (commercial use prohibited) #' 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 #' transformed (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 stemming 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 #' @example examples/setting.R #' @example examples/polyCub.exact.Gauss.R #' @import methods #' @importFrom sp plot #' @importFrom stats cov2cor #' @importFrom graphics lines #' @export polyCub.exact.Gauss <- function (polyregion, mean = c(0,0), Sigma = diag(2), plot = FALSE) { gpclibCheck(fatal=TRUE) if (inherits(polyregion, "owin")) { polyregion <- owin2gpc(polyregion) } else if (!inherits(polyregion, "gpc.poly")) { if (inherits(polyregion, "SpatialPolygons") && !requireNamespace("rgeos")) { stop("package ", sQuote("rgeos"), " is required to handle ", "\"SpatialPolygons\" input") } polyregion <- as(polyregion, "gpc.poly") } ## coordinate transformation so that the standard bivariat normal density ## can be used in integrations (cf. formula 26.3.22) polyregion@pts <- transform_pts(polyregion@pts, mean = mean, Sigma = Sigma) ## 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 <- vapply(X = triangleSets, FUN = function (triangles) { int <- 0 error <- 0 nTriangles <- nrow(triangles) - 2L for (i in seq_len(nTriangles)) { res <- .intTriangleAS(triangles[i+(0:2),]) int <- int + res error <- error + attr(res, "error") } c(int, nTriangles, error) }, FUN.VALUE = numeric(3L), USE.NAMES = FALSE) int <- sum(integrals[1,]) ## number of .V() evaluations (if there were no degenerate triangles) attr(int, "nEval") <- 6 * sum(integrals[2,]) ## approximate absolute integration error attr(int, "error") <- sum(integrals[3,]) return(int) } ########################### ### Auxiliary Functions ### ########################### ## transform coordinates according to Formula 26.3.22 transform_pts <- function (pts, mean, Sigma) { mx <- mean[1L] my <- mean[2L] rho <- cov2cor(Sigma)[1L,2L] sdx <- sqrt(Sigma[1L,1L]) sdy <- sqrt(Sigma[2L,2L]) lapply(pts, function (poly) { x0 <- (poly[["x"]] - mx) / sdx y0 <- (poly[["y"]] - my) / sdy list(x = (x0 + y0) / sqrt(2 + 2*rho), y = (y0 - x0) / sqrt(2 - 2*rho), hole = poly[["hole"]]) }) } ## calculates the integral of the standard bivariat normal over a triangle ABC .intTriangleAS <- function (xy) { if (anyDuplicated(xy)) # degenerate triangle return(structure(0, error = 0)) 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) { BmA <- B - A d <- vecnorm(BmA) h <- abs(B[2L]*A[1L] - A[2L]*B[1L]) / d # distance of AB to the origin if (d == 0 || h == 0) # degenerate triangle: A == B or 0, A, B on a line return(structure(0, error = 0)) k1 <- dotprod(A, BmA) / d k2 <- dotprod(B, BmA) / d V2 <- .V(h, abs(k2)) V1 <- .V(h, abs(k1)) res <- if (sign(k1) == sign(k2)) { ## A and B are on the same side of the normal line through 0 abs(V2 - V1) } else { V2 + V1 } 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) { if (k == 0) # degenerate triangle return(structure(0, error = 0)) 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), 2L, 2L) ) Qh <- pnorm(h, mean = 0, sd = 1, lower.tail = FALSE) return(Lh0rho - asin(rho)/2/pi - Qh/2) } polyCub/R/plotpolyf.R0000644000176200001440000001006413424535405014251 0ustar liggesusers################################################################################ ### plotpolyf: Plot Polygonal Domain on Image of Bivariate Function ### ### Copyright (C) 2013-2014,2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' 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}"} from package \pkg{spatstat}, ##' \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or ##' \pkg{gpclib}), as well as ##' \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, ##' and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. ##' (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.) ##' @param f a two-dimensional real-valued 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 color 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[lattice: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 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 = 2L) ## 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 <- seq(xlim[1L], xlim[2L], length.out = npixel[1L]) ygrid <- seq(ylim[1L], ylim[2L], length.out = npixel[2L]) 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[1L], npixel[2L]), col=col, xlab="x", ylab="y", asp=1) plot_polyregion(polyregion, lwd=lwd, add=TRUE) } } polyCub/R/tools.R0000644000176200001440000000536013357125754013373 0ustar liggesusers################################################################################ ### Internal Functions ### ### Copyright (C) 2009-2015,2017 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' 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? ##' @importFrom sp Polygons SpatialPolygons plot ##' @importFrom graphics polygon 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")) { 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)) if (inherits(polyregion, "owin")) ## && ! "plot.owin" %in% getNamespaceInfo("spatstat", "S3methods") plot <- spatstat::plot.owin # spatstat <1.33-0 has no registration ## plot call which works for "SpatialPolygons" and "owin" plot(polyregion, lwd=lwd, axes=TRUE, main="", add=add) } } polyCub/R/coerce-gpc-methods.R0000644000176200001440000001127513357664114015703 0ustar liggesusers################################################################################ ### Conversion between polygonal "owin" and "gpc.poly" ### ### Copyright (C) 2012-2015,2017-2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' Conversion between polygonal \code{"owin"} and \code{"gpc.poly"} ##' ##' 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. ##' @name coerce-gpc-methods ##' @rdname coerce-gpc-methods ##' @keywords spatial methods ##' @import methods ##' @export ##' @examples ##' if (gpclibPermit() && require("spatstat")) { ##' ## use example polygons from ##' example(plotpolyf, ask = FALSE) ##' ##' letterR # a simple "xylist" ##' letterR.owin <- owin(poly = letterR) ##' letterR.gpc_from_owin <- owin2gpc(letterR.owin) ##' letterR.xylist_from_gpc <- xylist(letterR.gpc_from_owin) ##' stopifnot(all.equal(letterR, lapply(letterR.xylist_from_gpc, "[", 1:2))) ##' letterR.owin_from_gpc <- as.owin(letterR.gpc_from_owin) ##' stopifnot(all.equal(letterR.owin, letterR.owin_from_gpc)) ##' } owin2gpc <- function (object) { object <- spatstat::as.polygonal(object) ## determine hole flags of the individual polygons hole <- spatstat::summary.owin(object)$areas < 0 ## reverse vertices and set hole flags pts <- mapply( FUN = function (poly, hole) { list(x = rev.default(poly$x), y = rev.default(poly$y), hole = hole) # or spatstat.utils::is.hole.xypolygon(poly) }, poly = object$bdry, hole = hole, 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[spatstat]{owin}}. ##' @rdname coerce-gpc-methods ##' @export gpc2owin <- function (object, ...) { ## first convert to an "owin" without checking areas etc. ## to determine the hole status according to vertex order (area) res <- spatstat::owin(poly = object@pts, check = FALSE) holes_owin <- spatstat::summary.owin(res)$areas < 0 ## or directly lapply spatstat.utils::is.hole.xypolygon ## 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 spatstat::owin(poly = bdry, ...) } ##' @inheritParams gpc2owin ##' @param W an object of class \code{"gpc.poly"}. ##' @rdname coerce-gpc-methods ##' @export ##' @rawNamespace if(getRversion() >= "3.6.0") { # delayed registration ##' S3method(spatstat::as.owin, gpc.poly) ##' } as.owin.gpc.poly <- function (W, ...) { gpc2owin(W, ...) } ## 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.R0000644000176200001440000000451313357346465014131 0ustar liggesusers################################################################################ ### Integration of the Isotropic Gaussian Density over Circular Domains ### ### Copyright (C) 2013-2014 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' 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 a circular domain ##' via the cumulative distribution function \code{pchisq} of the (non-central) ##' Chi-Squared distribution (Abramowitz and Stegun, 1972, Formula 26.3.24). ##' ##' @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() && requireNamespace("spatstat")) { ##' ## 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.R0000644000176200001440000001042513424526205013055 0ustar liggesusers################################################################################ ### Package Setup ### ### Copyright (C) 2009-2014,2018-2019 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ #' Cubature over Polygonal Domains #' #' The \R package \pkg{polyCub} implements \emph{cubature} #' (numerical integration) over \emph{polygonal} domains. #' It solves the problem of integrating a continuously differentiable #' function \eqn{f(x,y)} over simple closed polygons. #' #' \pkg{polyCub} provides the following cubature methods, #' which can either be called explicitly or via the generic #' \code{\link{polyCub}} function: #' \describe{ #' \item{\code{\link{polyCub.SV}}:}{ #' General-purpose \emph{product Gauss cubature} (Sommariva and Vianello, 2007) #' } #' \item{\code{\link{polyCub.midpoint}}:}{ #' Simple \emph{two-dimensional midpoint rule} based on #' \code{\link[spatstat]{as.im.function}} from \pkg{spatstat} #' (Baddeley and Turner, 2005) #' } #' \item{\code{\link{polyCub.iso}}:}{ #' Adaptive cubature for \emph{radially symmetric functions} #' via line \code{\link{integrate}()} along the polygon boundary #' (Meyer and Held, 2014, Supplement B, Section 2.4). #' } #' \item{\code{\link{polyCub.exact.Gauss}}:}{ #' Accurate (but slow) integration of the \emph{bivariate Gaussian density} #' based on polygon triangulation (via \code{\link[gpclib]{tristrip}} from #' \pkg{gpclib}) and (numerous) evaluations of cumulative densities (via #' \code{\link[mvtnorm]{pmvnorm}} from package \pkg{mvtnorm}). #' Note that there is also a function \code{\link{circleCub.Gauss}} #' to integrate the \emph{isotropic} Gaussian density over a #' \emph{circular domain}. #' } #' } #' A more detailed description and benchmark experiment of the above cubature #' methods can be found in the \code{vignette("polyCub")} and in #' Meyer (2010, Section 3.2). #' #' @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{https://doi.org/10.1214/14-AOAS743}, #' \href{https://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.\cr #' DOI-Link: \url{https://doi.org/10.1007/s10543-007-0131-2} #' @docType package #' @name polyCub-package #' @seealso #' \code{vignette("polyCub")} #' #' For the special case of a rectangular domain along the axes #' (e.g., a bounding box), the \pkg{cubature} package is more appropriate. 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} License Acceptance ##' ##' Similar to the handling in package \pkg{maptools}, these functions ##' explicitly accept the restricted \pkg{gpclib} license (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.R0000644000176200001440000000727713357664114015563 0ustar liggesusers################################################################################ ### as.owin.SpatialPolygons: Coerce "SpatialPolygons" to "owin" ### ### Copyright (C) 2012-2013,2015,2017-2018 Sebastian Meyer ### ### This file is 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 https://www.R-project.org/Licenses/. ################################################################################ ##' Coerce \code{"SpatialPolygons"} to \code{"owin"} ##' ##' Package \pkg{polyCub} implements \code{coerce}-methods ##' (\code{as(object, Class)}) to convert \code{"\linkS4class{SpatialPolygons}"} ##' (or \code{"\linkS4class{Polygons}"} or \code{"\linkS4class{Polygon}"}) ##' to \code{"\link[spatstat:owin.object]{owin}"}. ##' They are also available as \code{as.owin.*} functions to support ##' \code{\link{polyCub.midpoint}}. However, these are no registered S3 methods ##' for \code{\link[spatstat]{as.owin}}, since package \pkg{spatstat} is ##' optional. ##' Note that the \pkg{maptools} package contains an alternative implementation ##' of coercion from \code{"SpatialPolygons"} to \code{"owin"} (and reverse), ##' and \R will use the S4 \code{coerce}-method that was loaded last, ##' and prefer the \code{as.owin.SpatialPolygons} S3-method exported from ##' \pkg{maptools} if attached. ##' @author Sebastian Meyer ##' @keywords spatial methods ##' @name coerce-sp-methods ##' @rdname coerce-sp-methods ##' @import methods ##' @importClassesFrom sp Polygon Polygons SpatialPolygons owin ##' @exportMethod coerce ##' @examples ##' if (require("spatstat") && require("sp")) { ##' diamond <- list(x = c(1,2,1,0), y = c(1,2,3,2)) # anti-clockwise ##' diamond.owin <- owin(poly = diamond) ##' diamond.sp <- Polygon(lapply(diamond, rev)) # clockwise ##' diamond.owin_from_sp <- as(diamond.sp, "owin") ##' stopifnot(all.equal(diamond.owin, diamond.owin_from_sp)) ##' ##' ## similarly works for Polygons and SpatialPolygons ##' diamond.Ps <- as(diamond.sp, "Polygons") ##' stopifnot(identical(diamond.owin, as.owin(diamond.Ps))) ##' diamond.SpPs <- SpatialPolygons(list(diamond.Ps)) ##' stopifnot(identical(diamond.owin, as.owin(diamond.SpPs))) ##' } NULL ##' @param W an object of class \code{"SpatialPolygons"}, ##' \code{"Polygons"}, or \code{"Polygon"}. ##' @param ... further arguments passed to \code{\link[spatstat]{owin}}. ##' @rdname coerce-sp-methods ##' @export ##' @rawNamespace if(getRversion() >= "3.6.0") { # delayed registration ##' S3method(spatstat::as.owin, SpatialPolygons) ##' S3method(spatstat::as.owin, Polygons) ##' S3method(spatstat::as.owin, Polygon) ##' } as.owin.SpatialPolygons <- function (W, ...) spatstat::owin(poly = xylist.SpatialPolygons(W), ...) ##' @rdname coerce-sp-methods ##' @export as.owin.Polygons <- function (W, ...) spatstat::owin(poly = xylist.Polygons(W), ...) ##' @rdname coerce-sp-methods ##' @export as.owin.Polygon <- function (W, ...) spatstat::owin(poly = xylist.Polygon(W), ...) ##' @name coerce,SpatialPolygons,owin-method ##' @rdname coerce-sp-methods setAs(from = "SpatialPolygons", to = "owin", def = function (from) as.owin.SpatialPolygons(from)) ##' @name coerce,Polygons,owin-method ##' @rdname coerce-sp-methods setAs(from = "Polygons", to = "owin", def = function (from) as.owin.Polygons(from)) ##' @name coerce,Polygon,owin-method ##' @rdname coerce-sp-methods setAs(from = "Polygon", to = "owin", def = function (from) as.owin.Polygon(from)) ##' @name coerce,Polygon,Polygons-method ##' @rdname coerce-sp-methods setAs(from = "Polygon", to = "Polygons", def = function (from) Polygons(list(from), "Polygon")) polyCub/vignettes/0000755000176200001440000000000013427003213013672 5ustar liggesuserspolyCub/vignettes/polyCub.Rmd0000644000176200001440000002557313426777177016021 0ustar liggesusers--- title: "Getting started with polyCub" author: "Sebastian Meyer" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with polyCub} %\VignetteEngine{knitr::rmarkdown} --- ```{R setup, include = FALSE, purl = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` The R package **polyCub** implements *cubature* (numerical integration) over *polygonal* domains. It solves the problem of integrating a continuously differentiable function f(x,y) over simple closed polygons. For the special case of a rectangular domain along the axes, the package [**cubature**](https://CRAN.R-project.org/package=cubature) is more appropriate (cf. [`CRAN Task View: Numerical Mathematics`](https://CRAN.R-project.org/view=NumericalMathematics)). ## Polygon representations The integration domain is described by a polygonal boundary (or multiple polygons, including holes). Various R packages for spatial data analysis provide classes for polygons. The implementations differ in vertex order (which direction represents a hole) and if the first vertex is repeated. All of **polyCub**'s cubature methods understand * `"owin"` from package [**spatstat**](https://CRAN.R-project.org/package=spatstat), * `"gpc.poly"` from [**rgeos**](https://CRAN.R-project.org/package=rgeos) (or [**gpclib**](https://CRAN.R-project.org/package=gpclib)), and * `"SpatialPolygons"` from package [**sp**](https://CRAN.R-project.org/package=sp). Internally, **polyCub** uses its auxiliary `xylist()` function to extract a plain list of lists of vertex coordinates from these classes, such that vertices are ordered anticlockwise and the first vertex is not repeated (i.e., the `"owin"` convention). ## Cubature methods The following cubature methods are implemented in **polyCub**: 1. `polyCub.SV()`: Product Gauss cubature 2. `polyCub.midpoint()`: Two-dimensional midpoint rule 3. `polyCub.iso()`: Adaptive cubature for radially symmetric functions $f(x,y) = f_r(\lVert(x-x_0,y-y_0)\rVert)$ 4. `polyCub.exact.Gauss()`: Accurate (but slow) integration of the bivariate Gaussian density The following section details and illustrates the different cubature methods. ## Illustrations ```{R} library("polyCub") ``` We consider the integration of a function f(x,y) which all of the above cubature methods can handle: an isotropic zero-mean Gaussian density. **polyCub** expects the integrand f to take a two-column coordinate matrix as its first argument (as opposed to separate arguments for the x and y coordinates), so: ```{R example-f} f <- function (s, sigma = 5) { exp(-rowSums(s^2)/2/sigma^2) / (2*pi*sigma^2) } ``` We use a simple hexagon as polygonal integration domain, here specified via an `"xylist"` of vertex coordinates: ```{R example-polygon} hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) ``` An image of the function and the integration domain can be produced using **polyCub**'s rudimentary (but convenient) plotting utility: ```{R example, fig.width = 3, fig.height = 2.5} plotpolyf(hexagon, f, xlim = c(-8,8), ylim = c(-8,8)) ``` ### 1. Product Gauss cubature: `polyCub.SV()` The **polyCub** package provides an R-interfaced C-translation of "polygauss: Matlab code for Gauss-like cubature over polygons" (Sommariva and Vianello, 2013, ), an algorithm described in Sommariva and Vianello (2007, *BIT Numerical Mathematics*, ). The cubature rule is based on Green's integration formula and incorporates appropriately transformed weights and nodes of one-dimensional Gauss-Legendre quadrature in both dimensions, thus the name "product Gauss cubature". It is exact for all bivariate polynomials if the number of cubature nodes is sufficiently large (depending on the degree of the polynomial). For the above example, a reasonable approximation is already obtained with degree `nGQ = 3` of the one-dimensional Gauss-Legendre quadrature: ```{R product-Gauss, echo = -1, fig.show = "hold"} par(mar = c(3,3,1,2)) polyCub.SV(hexagon, f, nGQ = 3, plot = TRUE) ``` The involved nodes (displayed in the figure above) and weights can be extracted by calling `polyCub.SV()` with `f = NULL`, e.g., to determine the number of nodes: ```{R} nrow(polyCub.SV(hexagon, f = NULL, nGQ = 3)[[1]]$nodes) ``` For illustration, we create a variant of `polyCub.SV()`, which returns the number of function evaluations as an attribute: ```{R} polyCub.SVn <- function (polyregion, f, ..., nGQ = 20) { nw <- polyCub.SV(polyregion, f = NULL, ..., nGQ = nGQ) ## nw is a list with one element per polygon of 'polyregion' res <- sapply(nw, function (x) c(result = sum(x$weights * f(x$nodes, ...)), nEval = nrow(x$nodes))) structure(sum(res["result",]), nEval = sum(res["nEval",])) } polyCub.SVn(hexagon, f, nGQ = 3) ``` We can use this function to investigate how the accuracy of the approximation depends on the degree `nGQ` and the associated number of cubature nodes: ```{R} for (nGQ in c(1:5, 10, 20)) { result <- polyCub.SVn(hexagon, f, nGQ = nGQ) cat(sprintf("nGQ = %2i: %.12f (n=%i)\n", nGQ, result, attr(result, "nEval"))) } ``` ### 2. Two-dimensional midpoint rule: `polyCub.midpoint()` The two-dimensional midpoint rule in **polyCub** is a simple wrapper around `as.im.function()` and `integral.im()` from package **spatstat**. In other words, the polygon is represented by a binary pixel image and the integral is approximated as the sum of (pixel area * f(pixel midpoint)) over all pixels whose midpoint is part of the polygon. To use `polyCub.midpoint()`, we need to convert our polygon to **spatstat**'s "owin" class: ```{R, message = FALSE} library("spatstat") hexagon.owin <- owin(poly = hexagon) ``` Using a pixel size of `eps = 0.5` (here yielding 270 pixels), we obtain: ```{R midpoint, echo = -1, fig.show = "hold"} par(mar = c(3,3,1,3), xaxs = "i", yaxs = "i") polyCub.midpoint(hexagon.owin, f, eps = 0.5, plot = TRUE) ``` ### 3. Adaptive cubature for *isotropic* functions: `polyCub.iso()` A radially symmetric function can be expressed in terms of the distance r from its point of symmetry: f(r). If the antiderivative of r times f(r), called `intrfr()`, is analytically available, Green's theorem leads us to a cubature rule which only needs *one-dimensional* numerical integration. More specifically, `intrfr()` will be `integrate()`d along the edges of the polygon. The mathematical details are given in Meyer and Held (2014, *The Annals of Applied Statistics*, , Supplement B, Section 2.4). For the bivariate Gaussian density `f` defined above, the integral from 0 to R of `r*f(r)` is analytically available as: ```{R} intrfr <- function (R, sigma = 5) { (1 - exp(-R^2/2/sigma^2))/2/pi } ``` With this information, we can apply the cubature rule as follows: ```{R} polyCub.iso(hexagon, intrfr = intrfr, center = c(0,0)) ``` Note that we do not even need the original function `f`. If `intrfr()` is missing, it can be approximated numerically using `integrate()` for `r*f(r)` as well, but the overall integration will then be much less efficient than product Gauss cubature. Package **polyCub** exposes a C-version of `polyCub.iso()` for use by other R packages (notably [**surveillance**](https://CRAN.R-project.org/package=surveillance)) via `LinkingTo: polyCub` and `#include `. This requires the `intrfr()` function to be implemented in C as well. See for an example. ### 4. Integration of the *bivariate Gaussian density*: `polyCub.exact.Gauss()` Abramowitz and Stegun (1972, Section 26.9, Example 9) offer a formula for the integral of the bivariate Gaussian density over a triangle with one vertex at the origin. This formula can be used after triangulation of the polygonal domain (**polyCub** currently uses `tristrip()` from the [**gpclib**](https://CRAN.R-project.org/package=gpclib) package). The core of the formula is an integral of the bivariate Gaussian density with zero mean, unit variance and some correlation over an infinite rectangle [h, Inf] x [0, Inf], which can be computed accurately using `pmvnorm()` from the [**mvtnorm**](https://CRAN.R-project.org/package=mvtnorm) package. For the above example, we obtain: ```{R} gpclibPermit() # accept gpclib license (prohibits commercial use) polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)) ``` The required triangulation as well as the numerous calls of `pmvnorm()` make this integration algorithm quiet cumbersome. For large-scale integration tasks, it is thus advisable to resort to the general-purpose product Gauss cubature rule `polyCub.SV()`. Note: **polyCub** provides an auxiliary function `circleCub.Gauss()` to calculate the integral of an *isotropic* Gaussian density over a *circular* domain (which requires nothing more than a single call of `pchisq()`). ## Benchmark We use the last result from `polyCub.exact.Gauss()` as a reference value and tune the number of cubature nodes in `polyCub.SV()` and `polyCub.midpoint()` until the absolute error is below 10^-8. This leads to `nGQ = 4` for product Gauss cubature and a 1200 x 1200 pixel image for the midpoint rule. For `polyCub.iso()`, we keep the default tolerance levels of `integrate()`. For comparison, we also run `polyCub.iso()` without the analytically derived `intrfr` function, which leads to a double-`integrate` approximation. The median runtimes [ms] of the different cubature methods are given below. ```{r benchmark, purl = FALSE, eval = identical(Sys.getenv("NOT_CRAN"), "true")} benchmark <- microbenchmark::microbenchmark( SV = polyCub.SV(hexagon.owin, f, nGQ = 4), midpoint = polyCub.midpoint(hexagon.owin, f, dimyx = 1200), iso = polyCub.iso(hexagon.owin, intrfr = intrfr, center = c(0,0)), iso_double_approx = polyCub.iso(hexagon.owin, f, center = c(0,0)), exact = polyCub.exact.Gauss(hexagon.owin, mean = c(0,0), Sigma = 5^2*diag(2)), times = 6, check = function (values) all(abs(unlist(values) - 0.274144773813434) < 1e-8)) ``` ```{r, purl = FALSE, eval = FALSE} summary(benchmark, unit = "ms")[c("expr", "median")] ``` ```{r, purl = FALSE, echo = FALSE, eval = identical(Sys.getenv("NOT_CRAN"), "true")} knitr::kable(summary(benchmark, unit = "ms")[c("expr", "median")], digits = 2) ``` The general-purpose SV-method is the clear winner of this small competition. A disadvantage of that method is that the number of cubature nodes needs to be tuned manually. This also holds for the midpoint rule, which is by far the slowest option. In contrast, the "iso"-method for radially symmetric functions is based on R's `integrate()` function, which implements automatic tolerance levels. Furthermore, the "iso"-method can also be used with "spiky" integrands, such as a heavy-tailed power-law kernel $f(r) = (r+1)^{-2}$. polyCub/README.md0000644000176200001440000000641213426604677013170 0ustar liggesusers # polyCub The [R](https://www.r-project.org/) package **polyCub** implements *cubature* (numerical integration) over *polygonal* domains. It solves the problem of integrating a continuously differentiable function f(x,y) over simple closed polygons. For the special case of a rectangular domain along the axes, the [**cubature**](https://CRAN.R-project.org/package=cubature) package is more appropriate (cf. [`CRAN Task View: Numerical Mathematics`](https://CRAN.R-project.org/view=NumericalMathematics)). ## Installation You can install [polyCub from CRAN](https://CRAN.R-project.org/package=polyCub) via: ```R install.packages("polyCub") ``` To install the development version from the GitHub repository, use: ```R ## install.packages("remotes") remotes::install_github("bastistician/polyCub") ``` ## Usage The basic usage is: ```r library("polyCub") polyCub(polyregion, f) ``` * `polyregion` represents the integration domain as an object of class `"owin"` (from **spatstat**), "`gpc.poly`" (from **gpclib** or **rgeos**), or `"SpatialPolygons"` (from **sp**), or even as a plain list of lists of vertex coordinates (`"xylist"`). * `f` is the integrand and needs to take a two-column coordinate matrix as its first argument. The `polyCub()` function by default calls `polyCub.SV()`, a C-implementation of *product Gauss cubature*. The various implemented cubature methods can also be called directly. ### Implemented cubature methods 1. `polyCub.SV()`: General-purpose **product Gauss cubature** (Sommariva and Vianello, 2007, *BIT Numerical Mathematics*, ) 2. `polyCub.midpoint()`: Simple **two-dimensional midpoint rule** based on [**spatstat**](https://CRAN.R-project.org/package=spatstat)`::as.im.function()` 3. `polyCub.iso()`: Adaptive **cubature for radially symmetric functions** via line `integrate()` along the polygon boundary (Meyer and Held, 2014, *The Annals of Applied Statistics*, , Supplement B, Section 2.4) 4. `polyCub.exact.Gauss()`: Accurate (but slow) **integration of the bivariate Gaussian density** based on polygon triangulation and [**mvtnorm**](https://CRAN.R-project.org/package=mvtnorm)`::pmvnorm()` For details and illustrations see the `vignette("polyCub")` in the installed package or [on CRAN](https://CRAN.R-project.org/package=polyCub/vignettes/polyCub.html). ## Applications The **polyCub** package evolved from the need to integrate so-called spatial interaction functions (Gaussian or power-law kernels) over the observation region (an administrative shapefile) of a spatio-temporal point process. Such epidemic models are implemented in [**surveillance**](https://CRAN.R-project.org/package=surveillance). **polyCub** also powers phylogeographic analyses in [**rase**](https://CRAN.R-project.org/package=rase). ## Feedback Contributions are welcome! Please submit suggestions or report bugs at or via e-mail to `maintainer("polyCub")`. Note that pull requests should only be submitted after discussion of the underlying issue. ## License The **polyCub** package is free and open source software, licensed under the GPLv2. polyCub/MD50000644000176200001440000000552613427056412012213 0ustar liggesusersad8c4410d9ccd558941e89e41eefd1be *DESCRIPTION ee2d8b4e51d1f3d9ce9d0ee78ef6ad59 *NAMESPACE 0121d09bedbb99fd7230ad9720d7d69f *NEWS.md e2910752918f441d614f125bd45bb4e9 *R/circleCub.R e87d4a6ee50519dc8b04c10802aa2e50 *R/coerce-gpc-methods.R d23692f1523efde88954b2711c40415c *R/coerce-sp-methods.R 08131caa4fdeb68ece69fb8f3e75587a *R/plotpolyf.R 35f047bb58410336590e336781abc1a1 *R/polyCub.R 5fbe76889ecad2d7603c45cf3ff49c0a *R/polyCub.SV.R fb6c81b17199f9f5d8cc3cb14c09592b *R/polyCub.exact.Gauss.R e6c1492486e719ee3d5bee53402cfae4 *R/polyCub.iso.R 4474cc8699844b539e38c6b93e9abf4c *R/polyCub.midpoint.R 75a1bb73253360d3ffdbb005b55f083f *R/sysdata.rda 2dacaa39cf8fecb099131e3fde20a071 *R/tools.R 976e774ec2bf30606f9bfd55f2c8bcc8 *R/xylist.R 20dc062bdc3b089d9080fe529579e868 *R/zzz.R af82ef9f177e24b3edec1e3419949c53 *README.md 55ce2e115aaf8ffa9ec23b4ffcf1166c *build/vignette.rds fd006470e6e4c42a511075a6f858c796 *inst/CITATION 94d9a80c5c3edd4282a845d88cc2b7c4 *inst/doc/polyCub.R 5d42228b0f873c9cdcf960f122bdf302 *inst/doc/polyCub.Rmd aadf4bb5261d009932804e3dece43e10 *inst/doc/polyCub.html af7c7fdb25a9f3fc0db625dbc9f26307 *inst/include/polyCubAPI.h 33a6ad9634c6d4e248a725957336149b *man/checkintrfr.Rd 5fdf2b130ae18b7b8e6fd7e48e42b6f7 *man/circleCub.Gauss.Rd 76f9af96889c337280fcacea18c2990e *man/coerce-gpc-methods.Rd 9e2edc89689654b1c2ca01e684cf4de6 *man/coerce-sp-methods.Rd 323f56fe3449f60180325c6263454377 *man/dotprod.Rd cf49b62c6d4f953ca6284afd31382b33 *man/figures/logo.png 2967ac23ff22ee87b195fb03d8bd0e00 *man/gpclibPermit.Rd db65b0e51cfcb8f175e6a32dc5c495e6 *man/isClosed.Rd b31e8ec92525bba018a7368f2d270ce2 *man/isScalar.Rd ff7535bf7ac7c13933c14a9ab3b454f2 *man/plot_polyregion.Rd 8ff1b20a8f01868a395e81aec741d7f0 *man/plotpolyf.Rd 7ebd070cdeba3e794ad4440e4150fd16 *man/polyCub-package.Rd e476d285200901dfaa3c7175eeab3e28 *man/polyCub.Rd 500aace3a064785abf3a1b85d84ec0f1 *man/polyCub.SV.Rd 37a1b35f9063adb2048664716211a964 *man/polyCub.exact.Gauss.Rd 431d0646a0d2c96bb90bfbf8cc53a5d6 *man/polyCub.iso.Rd fb4071556ede1c98dc366bf3a953425e *man/polyCub.midpoint.Rd ebe7344df64a58efe83cbf30df3cf174 *man/polygauss.Rd 3e57be2294c537ed441d6273872bd716 *man/vecnorm.Rd 2b9d9db445fbbaca1411a2273c1198fe *man/xylist.Rd 8ab51266adc6ede5ffb503ad17fb360a *src/init.c bd2782f92e09d64dbea9e87f10b66f97 *src/polyCub.SV.c ce25a1a76b4cf52a0f34a1352640227d *src/polyCub.SV.h 2ef3ee5c813c5281bec75b33eb6cb589 *src/polyCub.iso.c c16fcda4cc1fa1bf7c4e7cb9b97294d3 *src/polyCub.iso.h 3e4e9e53ad2f425939503fd77e030cd2 *tests/test-all.R 673cd0874ece8c19399eaf853af0457a *tests/testthat/polyiso_powerlaw.c f9944d29a2f868a9a88aeb2945616734 *tests/testthat/test-NWGL.R 45d80abea161a05b50876bdb0e42894d *tests/testthat/test-polyCub.R cb26d6f1b02203151bdc0c02d3761602 *tests/testthat/test-polyiso.R f7e4b3e0f89575d6c38639b9e36edd8c *tests/testthat/test-regression.R 5d42228b0f873c9cdcf960f122bdf302 *vignettes/polyCub.Rmd polyCub/build/0000755000176200001440000000000013427003213012761 5ustar liggesuserspolyCub/build/vignette.rds0000644000176200001440000000033013427003213015314 0ustar liggesusersmP0  jbOKH^'iv}ם\BN K'a1,f{?qƔfD~+8krh@*5grw@3/ӌW {{~kBySrL0v1#aQx1aԧZj?ȢV?0hꢗV.@D~b;ωpolyCub/DESCRIPTION0000644000176200001440000000351213427056412013402 0ustar liggesusersPackage: polyCub Title: Cubature over Polygonal Domains Version: 0.7.1 Date: 2019-02-07 Authors@R: c( person("Sebastian", "Meyer", email = "seb.meyer@fau.de", role = c("aut","cre","trl"), comment = c(ORCID = "0000-0002-1791-9449")), person("Leonhard", "Held", email = "Leonhard.Held@uzh.ch", role = "ths"), person("Michael", "Hoehle", email = "hoehle@math.su.se", role = "ths") ) Description: Numerical integration of continuously differentiable functions f(x,y) over simple closed polygonal domains. The following cubature methods are implemented: product Gauss cubature (Sommariva and Vianello, 2007, ), the simple two-dimensional midpoint rule (wrapping 'spatstat' functions), adaptive cubature for radially symmetric functions via line integrate() along the polygon boundary (Meyer and Held, 2014, , Supplement B), and integration of the bivariate Gaussian density based on polygon triangulation. For simple integration along the axes, the 'cubature' package is more appropriate. License: GPL-2 URL: https://github.com/bastistician/polyCub BugReports: https://github.com/bastistician/polyCub/issues Depends: R (>= 2.15.0), methods Imports: grDevices, graphics, stats, sp (>= 1.0-11) Suggests: spatstat, lattice, testthat, mvtnorm, statmod, rgeos, gpclib, cubature, knitr, rmarkdown, microbenchmark RoxygenNote: 6.1.1 VignetteBuilder: knitr, rmarkdown NeedsCompilation: yes Packaged: 2019-02-07 10:20:59 UTC; smeyer Author: Sebastian Meyer [aut, cre, trl] (), Leonhard Held [ths], Michael Hoehle [ths] Maintainer: Sebastian Meyer Repository: CRAN Date/Publication: 2019-02-07 16:30:02 UTC polyCub/man/0000755000176200001440000000000013424543542012450 5ustar liggesuserspolyCub/man/coerce-gpc-methods.Rd0000644000176200001440000000436013357143404016410 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/coerce-gpc-methods.R \name{coerce-gpc-methods} \alias{coerce-gpc-methods} \alias{owin2gpc} \alias{gpc2owin} \alias{as.owin.gpc.poly} \title{Conversion between polygonal \code{"owin"} and \code{"gpc.poly"}} \usage{ owin2gpc(object) gpc2owin(object, ...) as.owin.gpc.poly(W, ...) } \arguments{ \item{object}{an object of class \code{"gpc.poly"} or \code{"owin"}, respectively.} \item{...}{further arguments passed to \code{\link[spatstat]{owin}}.} \item{W}{an object of class \code{"gpc.poly"}.} } \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! } \examples{ if (gpclibPermit() && require("spatstat")) { ## use example polygons from example(plotpolyf, ask = FALSE) letterR # a simple "xylist" letterR.owin <- owin(poly = letterR) letterR.gpc_from_owin <- owin2gpc(letterR.owin) letterR.xylist_from_gpc <- xylist(letterR.gpc_from_owin) stopifnot(all.equal(letterR, lapply(letterR.xylist_from_gpc, "[", 1:2))) letterR.owin_from_gpc <- as.owin(letterR.gpc_from_owin) stopifnot(all.equal(letterR.owin, letterR.owin_from_gpc)) } } \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. } \author{ Sebastian Meyer } \keyword{methods} \keyword{spatial} polyCub/man/figures/0000755000176200001440000000000013422360357014113 5ustar liggesuserspolyCub/man/figures/logo.png0000644000176200001440000002467713422360357015601 0ustar liggesusersPNG  IHDRX? pHYsod IDATxyTոـauXeQPY\h!@$;FDH".\јnAd,*#,#0[:v߭oy֩iNSUTUOsx, pp)kA7WhF'BTz S؞=;zMִAӁ 4 ڼy@AՁ^ ̜ySuJ\Z;4vAH[h2;;3pͧ~@ 𷐟 {@z\ sw (z^ܖKϞyqo|yևWmL`1éȐS0rπA,Xظ@>1 :ixU[({իA>:uj7iѢ1+W~ͱcN(%8 XX` \ L 32k;3mڹxb))Ss E-z .C؝E.)ےѿ+ ĺuߑ:˖m \Zб='~6;g:a'6]a1=>p'ͪQv ;I@`annwٝIzѸq*-=3s9r$d\ Ah " رX5mHd Z/-Zd?K-uoߐoNZj7Z=p#GlX# l9y;(4 ''ooʻfРdfdq'sŪU23[Q!ؒB 2}zswboP'~[oB͏߲|i(tA14KO=՜C ĈBZhW:_|#rpB[C0׵0/ɓO`֬tjbرc!ի.ͧsC?r?$lQO0XiGfQuѨsL 3wtKEE5?_áC!U?lǐE,dNv,!#Fsᗿl=!`(u᳥  7\,jXeB,1 )pVvRxI˷W} \nYChZFy۵_UV^oѻw .9snSZhcK5ąO.p7ͅ9sZng gўoӴi.V}Cyyi ,!&:6QrGma0ct3loAQĉQw( `.=,X ݦޠC=6O{-'Q燥龈5x[v1d w= OPS'brew+{A!P WICՅ>up6|8؄0N; sƇG!U0]5. }0Z|B3plX"BUYY+,'S Zg`\GЙuK33ˡp\l;ةR̠wo74 ֮- n;ePOj:\9  5ʥR0q,y ziWc^{íDn"ZlŠ!-:-m;Q2Qٜ\[_O&!},"~ dZ?K܅:e<2?  eBI@ftvmbEm?`Psv4Zm^#|I+$c̙s'8LAHxvhȡ9aS*M3mLee!UnL"pTU@m㰁pP1D}ZU^NN~W;† VMnbЧ:Rma׎xgX`Mx&Ǝ}뿏7~ch ~wT)(o,\]WW0~~1Pj5Gg:n {,7N \k3j#2228̓3F)5o[SZ*qrC2L.:3 Zl͸qo2o^u6I ܦ#C #7dN81aـmj_>3i'>qE^`#cǾΗ_B͏Lb`1>\O8^z%x}9>S*XNZ1f Zhʕ!aPnuK]e:mMCc23hnVXhqd#L2[VI R ~ r(pL7QVnu1v,]9sTX$0Nv@DZE+5}),Y2s1$m,1ą!nvZ$4_¤՜7eR[e=]7Q$cKK˙1c AڷWI^.w*%WʅnJ_4Ve3tKJ*No =1vޫ oA"l:5'' 'nNA6QZb6nfՄev[!''ի? <ub=U#f*pJh s@T&(0^U 窫k׏lX{y6Q{Ȧd;a O?vi O] Cόv:N%Z\:G,Zz 6W} L*8h* 4ʛ >"<|̙֭OҪUsmEUY3" ت /tegˡUDBVYgYe 2&b5..>ԩ/>yy(.>8Wns-t3;+nϭ8 sZSdy{^$7C\ȨQog"ʎJ| lh.܅@60vX8zKAHotļyᇯҭ[Hr{`zdB7ƣn=Ca0h+ArVƕ7A5J~6<4D_Vj˅@]z] C{Ȁ.q0:rVƕK YY6c\IY1֮"xb*g *x-Q2}Q'D}ߧ|Gu ,Eh'2`@*횟i]P ёB07c{m[-+1H֝66…ydvWv,esQqs>(on=ۡo'QޤH,r u2ҥ7|M6fժumӁ[& ԉ{iF#+!:!a'~dkl?ʜ9z[3L>_ aOcRZ5.)u2|& ŸD[3Vjldݺb.b k$ €}Xv.-iP (F',vq'ccLf\I(Ҽ%1DYRj%6Nff&͚UNǴzA u?"x@w]Nne!8(zVV{`k0un>%q%:3Zwgb{}JǑ#.tQU ]F"`~"5>hc ?`ߡTǍ>vc`]A9p2sv2 Sb<rOD{GV׼{}b!8 dvxmC_Or29c\ͫvRHv<:V/ICŮIԝvteڟDέL0ffۓ4y5{#ә'B%6b]ŭC\3;=BEff•%8GW}-ּ'ڹ6Gy{y]:u3 F> _N5p֍SH {KKB=zq81MwB= ?iWq< hF [o{ A|KhY(V4'7^ /̃7\?mx áвzv2L1 v 6GU#yT{H@mthcHvox?SA>+,+1te*{M"?zs\vJθ Gf4.>jLF$2mqQͫ`Ś~ڂX`'8XY~hd{}舺R.t*y$:V;ϸJQ= w?<4}.ylgmX`P1ʅFB)>Ӥd=;W9'iVfX`7bՏb=(8Ƀ%P^iXPJ=VĮthxk 5R#'ᔞCc[+ᔞ#qKcUVRe\ Lrp"p"ѕi!cě =D=F< ,.B;[Gpg -b98aԕvx,yl||X`o@D!lX}d22kdT"AKcjdїJ#Cs*n)D=DY@<+,V . j1 =S  !Ju(p,dy Q`$s`Oa G:I<=s΁\+0E>B>(S{S-$B[xʊbBF<񢰂tz>ѕin~JW[ !Xrͨofeͤ mćc^ E5>Gb=XCC"4.Qf&߉"htqv [Wvr{=j!uzDSH6^M/pM/.qhI,%wmŤjX`gZ,z**`X{:v Ǫ=W^f}Vޞ[3& !uZrkvfܧ)6ւY="{#B"Ct# !ZJQ``܅vgF2.FCk+[yd)n΄2Bm$ !2ʹBJ߅N%w(unf]fqZ`IװL,y'-I,ҩz܏(Ы9{^4Vu|DYe֩9RRŵ:ҵJ%]!uZz{(=^ , $.JTz +]!tY֎C`Ţ ^뱬9bYȴ \yOHX`Dz֗OS!X>{ g\h3%T3f}emo \ !BuֹVeo{gKp=H1jX2,A,h 8:(H܅N% i+ lq)W?δiO]Vف=bS\hܲ8q/yj%C !"VڑRjqh4t,Q6LQͫ^{FYu-+[{ q˒2?tqñz؆&Yp2v-phZI].(c:\fuY`I@"yu)|BN ,Err׻Fbi-`u)l#y 8=酸zq$FpTqScKeS{V׋B{V(Vj2qYb|{XOҿ:{ȉSXS' ;5SV p,k j)Ew&(i zyNA>NҾ~C؃RຶC؃B׵B-Tyb _K ,p,ZH]D=H ܱG &e<1)ז6" AfGy, 9D=JxZaL83cC8ڰfa ܣqiGq0(.M`-)RN  pcK(8(yq?>?VByÌ}}3,qPinXv1ˏm;* . -|whO" b&:)˶S%l8 Wn}旭,0 RT]'׵3o\ R+z5dڳr`BGsDإ6arӥ\[$v)s],#x;d5J0QdhgX,¿v1[Aq <~܇(i 8p<%s r.n K:Cl9 7L Yir}†`a(*jh =@fNRpQ!+5U?- |w+> 1ۏr8p~`ݺڪYd0cx@S(T_̙SZ)AYY@ z–B;GfLfmUr<1`,0{S>0 x}yu+ff2`cT|5!}VN~//Lmy pp= 7JٷCG)n_15 S`BA"y'3fx0r~;=x- )ЫXd9}ިL\hß/f͂y" 6%]o(b`7 {=ʻp :^-niVx6j~נ@AH?@;L ͞L ۔j \P$)ζnxު1> GGeT?+x,p bsLs1O&U"dѢ2z-gW3r6CiqmaЙʄN+acdF/͆ !lGmƄ#3 n=C(S}= 'CϞ[U-.-ZS0{Z FM2/QQ])hEؤr-/7̫M0b̛o Qaq46/ /,XyRX96hߩ!k@~>\Yr>#kLjCJOGi , XΝ0z4?Py>OZ }BAp90u*tdR`**w};j+QԵiY m1'yo2224/߆KG9oZkI;P{_ֶ؉ )f eIDAT9 c0"նmU nJ\ ^ C~>x6C$s, ,4>#-l4AM ާ-4 ;Ri9vVe8TQx  ܏ Bܲ{b| ,X g] c PᏮKrbVq: bwȞVW[gz^,-`ނ*nBpg!`_BAH„?ByBMzBwgUE-#ͪ!+sBF<a[0zb KC %gnuxB'3\csm 뿌B.7&BGcsԷõw?EPQ[" A-_SByעF A~ V0 |uDl~ <V ?q6R"l:?5oBE@Y3N4ANݰ xM8X>$ͯx k *Vu1a Y-3W f-;oB4B0xcRd  QIMl 쨂EŰӉ'j;\q'|# T_K&p-8Z[xMx ̪'mϽAp<#‹.t4(+2K6T˥59+MNpïGkC湕WC=3ύGXpND͍fM`6ح=Dۙup ߢ18[PsKڀ-U0'kغF=LPޭ!Bбu~] Ja_k `w3B)G߄k MA]M}5i~mh:&whؚgm_dd|u^]V#Qh:c[}x\$ ɢu>d}>&ը\5iL΁<&tcB:mEͶSӇ`4ʻr  \N@mM|ZmEl[Rô44Nxx#&龈U^@FfC,8;oB$io"Y o)VAeh"buy! 0F+!|Zc_[">Cs'{Z! l rT I!vprPddX~ˋJ u0_IG3:1ihK<[ ԋG,+7!1x4.'I#u! Sat$z^o~za$F<.B )l]c(]05' 7:4!Q`s ->Yf5mӡu=RRX߁F,N|/(5w*S^JLۚvUR6=D% 0 ؛([K)`hHa#x m)La^ƾ_|Q5" q!!-`zޘTďO"ȭ# l9my`Ltr4IP]kB8:=?%8*lը`\X७P? P^i7ٟ!gQP Gm"MvsPNB CA:z`?߃UETA?LpB;p`_,+i|wAo>Yr;QHc <[PaQalпUm'J+੥0UX\ZYvQg=]Kgsd.n05(JpɈm!-aпmu(g;a{l[D:~z,Dؽd$IN HK`ʇ܊[&"2v7PiwQa/ʫvX Qg?_̈́߆,R~,A\XTQ`dH %FwV-1pm VQbipP0z {:L7qsMr9XZDSlFԉiٙpcxBh1Aq)L^ i~SQ_ r Hsjujy  P1@43$к*%FbABg[^^lApThJ uT5e  hY~A?:X8?tIENDB`polyCub/man/dotprod.Rd0000644000176200001440000000056213106557311014411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tools.R \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.Rd0000644000176200001440000000415113424543542014355 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.R \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 domain. The following classes are supported: \code{"\link[spatstat]{owin}"} from package \pkg{spatstat}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or \pkg{gpclib}), as well as \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.)} \item{f}{a two-dimensional real-valued function to be integrated over \code{polyregion}. 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.\cr 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 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{ The wrapper function \code{polyCub} can be used to call specific cubature methods via its \code{method} argument. It calls \code{\link{polyCub.SV}} by default, which implements general-purpose product Gauss cubature. } \seealso{ Details and examples in the \code{vignette("polyCub")} and on the method-specific help pages. Other polyCub-methods: \code{\link{polyCub.SV}}, \code{\link{polyCub.exact.Gauss}}, \code{\link{polyCub.iso}}, \code{\link{polyCub.midpoint}} } \concept{polyCub-methods} \keyword{math} \keyword{spatial} polyCub/man/plot_polyregion.Rd0000644000176200001440000000152313424535405016164 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tools.R \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}"} from package \pkg{spatstat}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or \pkg{gpclib}), as well as \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.)} \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.Rd0000644000176200001440000000053413106557311014406 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tools.R \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.Rd0000644000176200001440000000554313424526205015751 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{package} \name{polyCub-package} \alias{polyCub-package} \title{Cubature over Polygonal Domains} \description{ The \R package \pkg{polyCub} implements \emph{cubature} (numerical integration) over \emph{polygonal} domains. It solves the problem of integrating a continuously differentiable function \eqn{f(x,y)} over simple closed polygons. } \details{ \pkg{polyCub} provides the following cubature methods, which can either be called explicitly or via the generic \code{\link{polyCub}} function: \describe{ \item{\code{\link{polyCub.SV}}:}{ General-purpose \emph{product Gauss cubature} (Sommariva and Vianello, 2007) } \item{\code{\link{polyCub.midpoint}}:}{ Simple \emph{two-dimensional midpoint rule} based on \code{\link[spatstat]{as.im.function}} from \pkg{spatstat} (Baddeley and Turner, 2005) } \item{\code{\link{polyCub.iso}}:}{ Adaptive cubature for \emph{radially symmetric functions} via line \code{\link{integrate}()} along the polygon boundary (Meyer and Held, 2014, Supplement B, Section 2.4). } \item{\code{\link{polyCub.exact.Gauss}}:}{ Accurate (but slow) integration of the \emph{bivariate Gaussian density} based on polygon triangulation (via \code{\link[gpclib]{tristrip}} from \pkg{gpclib}) and (numerous) evaluations of cumulative densities (via \code{\link[mvtnorm]{pmvnorm}} from package \pkg{mvtnorm}). Note that there is also a function \code{\link{circleCub.Gauss}} to integrate the \emph{isotropic} Gaussian density over a \emph{circular domain}. } } A more detailed description and benchmark experiment of the above cubature methods can be found in the \code{vignette("polyCub")} and in Meyer (2010, Section 3.2). } \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{https://doi.org/10.1214/14-AOAS743}, \href{https://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.\cr DOI-Link: \url{https://doi.org/10.1007/s10543-007-0131-2} } \seealso{ \code{vignette("polyCub")} For the special case of a rectangular domain along the axes (e.g., a bounding box), the \pkg{cubature} package is more appropriate. } polyCub/man/checkintrfr.Rd0000644000176200001440000000377713357350331015254 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.iso.R \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}{a \code{function(R, ...)}, which implements the (analytical) antiderivative of \eqn{r f_r(r)} from 0 to \code{R}. The first argument must be vectorized but not necessarily named \code{R}.\cr If \code{intrfr} is missing, it will be approximated numerically via \code{\link{integrate}(function(r, ...) r * f(cbind(x0 + r, y0), ...), 0, R, ..., control=control)}, where \code{c(x0, y0)} is the \code{center} of isotropy. Note that \code{f} will \emph{not} be checked for isotropy.} \item{f}{a two-dimensional real-valued 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 (default), 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.Rd0000644000176200001440000000730313424543542016543 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.exact.Gauss.R \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 transformed (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 stemming 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{ The bivariate Gaussian density can be integrated based on a triangulation of the (transformed) polygonal domain, using 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: \eqn{(AOB+BOC-AOC)} or \eqn{(AOB-AOC-BOC)} or \eqn{(AOB+AOC-BOC)} or \eqn{(AOC+BOC-AOB)} or \ldots. However, the most time consuming step is the evaluation of \code{\link[mvtnorm]{pmvnorm}}. } \note{ The package \pkg{gpclib} is required to produce the \code{tristrip}, since this is not implemented in \pkg{rgeos} (as of version 0.3-25). The restricted license of \pkg{gpclib} (commercial use prohibited) has to be accepted explicitly via \code{\link{gpclibPermit}()} prior to using \code{polyCub.exact.Gauss}. } \examples{ ## a 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) ## a simple polygon as integration domain hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) ## quasi-exact integration based on gpclib::tristrip() and mvtnorm::pmvnorm() if (requireNamespace("mvtnorm") && gpclibPermit()) { hexagon.gpc <- new("gpc.poly", pts = lapply(hexagon, c, list(hole = FALSE))) plotpolyf(hexagon.gpc, f, xlim = c(-8,8), ylim = c(-8,8)) print(polyCub.exact.Gauss(hexagon.gpc, mean = c(0,0), Sigma = 5^2*diag(2), plot = TRUE), digits = 16) } } \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.SV}}, \code{\link{polyCub.iso}}, \code{\link{polyCub.midpoint}}, \code{\link{polyCub}} } \concept{polyCub-methods} \keyword{math} \keyword{spatial} polyCub/man/circleCub.Gauss.Rd0000644000176200001440000000335313357346465015731 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/circleCub.R \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 a circular domain via the cumulative distribution function \code{pchisq} of the (non-central) Chi-Squared distribution (Abramowitz and Stegun, 1972, Formula 26.3.24). } \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() && requireNamespace("spatstat")) { ## 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.Rd0000644000176200001440000000615213424543542016202 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.midpoint.R \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 a corresponding \code{\link[spatstat]{as.owin}}-method. Note that this includes polygons of the classes \code{"gpc.poly"} and \code{"\linkS4class{SpatialPolygons}"}, because \pkg{polyCub} defines methods \code{\link{as.owin.gpc.poly}} and \code{\link{as.owin.SpatialPolygons}}, respectively.} \item{f}{a two-dimensional real-valued 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{ ## a 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) ## a simple polygon as integration domain hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) if (require("spatstat")) { hexagon.owin <- owin(poly = hexagon) show_midpoint <- function (eps) { plotpolyf(hexagon.owin, f, xlim = c(-8,8), ylim = c(-8,8), use.lattice = FALSE) ## add evaluation points to plot with(as.mask(hexagon.owin, eps = eps), points(expand.grid(xcol, yrow), col = t(m), pch = 20)) title(main = paste("2D midpoint rule with eps =", eps)) } ## show nodes (eps = 0.5) show_midpoint(0.5) ## show pixel image (eps = 0.5) polyCub.midpoint(hexagon.owin, f, eps = 0.5, plot = TRUE) ## use a decreasing pixel size (increasing number of nodes) for (eps in c(5, 3, 1, 0.5, 0.3, 0.1)) cat(sprintf("eps = \%.1f: \%.7f\\n", eps, polyCub.midpoint(hexagon.owin, f, eps = eps))) } } \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.SV}}, \code{\link{polyCub.exact.Gauss}}, \code{\link{polyCub.iso}}, \code{\link{polyCub}} } \concept{polyCub-methods} \keyword{math} \keyword{spatial} polyCub/man/polyCub.iso.Rd0000644000176200001440000001453213424535405015151 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.iso.R \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}"} from package \pkg{spatstat}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or \pkg{gpclib}), as well as \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.)} \item{f}{a two-dimensional real-valued 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}{a \code{function(R, ...)}, which implements the (analytical) antiderivative of \eqn{r f_r(r)} from 0 to \code{R}. The first argument must be vectorized but not necessarily named \code{R}.\cr If \code{intrfr} is missing, it will be approximated numerically via \code{\link{integrate}(function(r, ...) r * f(cbind(x0 + r, y0), ...), 0, R, ..., control=control)}, where \code{c(x0, y0)} is the \code{center} of isotropy. Note that \code{f} will \emph{not} be checked for isotropy.} \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 upper bound 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 upper bound 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{ \code{polyCub.iso} numerically integrates a radially symmetric 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 approximates a line integral along the polygon boundary using \code{\link{integrate}}. The integrand requires the antiderivative of \eqn{r f_r(r)}), which should be supplied as argument \code{intrfr} (\code{f} itself is only required if \code{check.intrfr=TRUE}). The two-dimensional integration problem thereby reduces to an efficient adaptive quadrature in one dimension. If \code{intrfr} is not available analytically, \code{polyCub.iso} can use a numerical approximation (meaning \code{integrate} within \code{integrate}), but the general-purpose cubature method \code{\link{polyCub.SV}} might be more efficient in this case. 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' (not recommended) (intISOnum <- polyCub.iso(letterR, f, center = fcenter)) ## analytical 'intrfr' ## intrfr(R) = int_0^R r*f(r) dr, for f(r) = dexp(r), gives intrfr <- function (R, rate = 1) pgamma(R, 2, rate) / rate (intISOana <- polyCub.iso(letterR, f, intrfr = intrfr, center = fcenter, check.intrfr = TRUE)) ## f is only used to check 'intrfr' against a numerical approximation stopifnot(all.equal(intISOana, intISOnum, check.attributes = FALSE)) ### polygon area: f(r) = 1, f(x,y) = 1, center does not really matter ## intrfr(R) = int_0^R r*f(r) dr = int_0^R r dr = R^2/2 intrfr.const <- function (R) R^2/2 (area.ISO <- polyCub.iso(letterR, intrfr = intrfr.const, center = c(0,0))) if (require("spatstat")) { # check against area.owin() stopifnot(all.equal(area.owin(owin(poly = letterR)), area.ISO, check.attributes = FALSE)) } } \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{https://doi.org/10.1214/14-AOAS743}, \href{https://arxiv.org/abs/1308.5115}{arXiv:1308.5115} } \seealso{ \code{system.file("include", "polyCubAPI.h", package = "polyCub")} for a full C-implementation of this cubature method (for a \emph{single} polygon). The corresponding C-routine \code{polyCub_iso} can be used by other \R packages, notably \pkg{surveillance}, via \samp{LinkingTo: polyCub} (in the \file{DESCRIPTION}) and \samp{#include } (in suitable \file{/src} files). Note that the \code{intrfr} function must then also be supplied as a C-routine. An example can be found in the package tests. Other polyCub-methods: \code{\link{polyCub.SV}}, \code{\link{polyCub.exact.Gauss}}, \code{\link{polyCub.midpoint}}, \code{\link{polyCub}} } \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. } \concept{polyCub-methods} \keyword{math} \keyword{spatial} polyCub/man/xylist.Rd0000644000176200001440000000572713164400262014276 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/xylist.R \name{xylist} \alias{xylist} \alias{xylist.owin} \alias{xylist.gpc.poly} \alias{xylist.SpatialPolygons} \alias{xylist.Polygons} \alias{xylist.Polygon} \alias{xylist.default} \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{"\linkS4class{Polygons}"} from package \pkg{sp} (as well as \code{"\linkS4class{Polygon}"} and \code{"\linkS4class{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/polygauss.Rd0000644000176200001440000000531013164502650014760 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.SV.R \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.\cr DOI-Link: \url{https://doi.org/10.1007/s10543-007-0131-2} } \keyword{internal} polyCub/man/plotpolyf.Rd0000644000176200001440000000560213424535405014771 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/plotpolyf.R \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}"} from package \pkg{spatstat}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or \pkg{gpclib}), as well as \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.)} \item{f}{a two-dimensional real-valued 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}{color 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[lattice: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 (a rounded version of spatstat.data::letterR$bdry) letterR <- list( list(x = c(3.9, 3.8, 3.7, 3.5, 3.4, 3.5, 3.7, 3.8, 3.8, 3.7, 3.7, 3.5, 3.3, 2, 2, 2.7, 2.7, 2.9, 3, 3.3, 3.9), y = c(0.7, 1.1, 1.3, 1.7, 1.8, 1.9, 2.1, 2.3, 2.5, 2.8, 3, 3.2, 3.3, 3.3, 0.7, 0.7, 1.7, 1.7, 1.5, 0.7, 0.6)), list(x = c(2.6, 2.6, 3, 3.1, 3.2, 3.1, 3.1, 3), y = c(2.2, 2.7, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2)) ) ### 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.Rd0000644000176200001440000000102713165477132015363 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \name{gpclibPermit} \alias{gpclibPermit} \alias{gpclibPermitStatus} \title{\pkg{gpclib} License Acceptance} \usage{ gpclibPermit() gpclibPermitStatus() } \description{ Similar to the handling in package \pkg{maptools}, these functions explicitly accept the restricted \pkg{gpclib} license (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.Rd0000644000176200001440000001412313424543542014704 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/polyCub.SV.R \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}"} from package \pkg{spatstat}, \code{"\link[rgeos:gpc.poly-class]{gpc.poly}"} from \pkg{rgeos} (or \pkg{gpclib}), as well as \code{"\linkS4class{SpatialPolygons}"}, \code{"\linkS4class{Polygons}"}, and \code{"\linkS4class{Polygon}"} from package \pkg{sp}. (For these classes, \pkg{polyCub} knows how to get an \code{\link{xylist}}.)} \item{f}{a two-dimensional real-valued function to be integrated over \code{polyregion} (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{ ## a 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) ## a simple polygon as integration domain hexagon <- list( list(x = c(7.33, 7.33, 3, -1.33, -1.33, 3), y = c(-0.5, 4.5, 7, 4.5, -0.5, -3)) ) ## image of the function and integration domain plotpolyf(hexagon, f, xlim = c(-8,8), ylim = c(-8,8)) ## use a degree of nGQ = 3 and show the corresponding nodes polyCub.SV(hexagon, f, nGQ = 3, plot = TRUE) ## extract nodes and weights nw <- polyCub.SV(hexagon, f = NULL, nGQ = 3)[[1]] nrow(nw$nodes) ## manually apply the cubature rule sum(nw$weights * f(nw$nodes)) ## use an increasing number of nodes for (nGQ in c(1:5, 10, 20, 60)) cat(sprintf("nGQ = \%2i: \%.16f\\n", nGQ, polyCub.SV(hexagon, f, nGQ = nGQ))) ## polyCub.SV() is the default method used by the polyCub() wrapper polyCub(hexagon, f, nGQ = 3) # calls polyCub.SV() ### now using a simple *rectangular* integration domain rectangle <- list(list(x = c(-1, 7, 7, -1), y = c(-3, -3, 7, 7))) ## try rotation (may improve accuracy) opar <- par(mfrow = c(1,3)) polyCub.SV(rectangle, f, nGQ = 4, rotation = FALSE, plot = TRUE) title(main = "without rotation") polyCub.SV(rectangle, f, nGQ = 4, rotation = TRUE, plot = TRUE) title(main = "default rotation") polyCub.SV(rectangle, f, nGQ = 4, rotation = list(P = c(0,0), Q = c(2,-3)), plot = TRUE) title(main = "custom rotation") par(opar) ## comparison with cubature::adaptIntegrate() if (require("cubature")) { fc <- function (s, sigma = 5) exp(-sum(s^2)/2/sigma^2) / (2*pi*sigma^2) adaptIntegrate(f = fc, lowerLimit = c(-1, -3), upperLimit = c(7, 7)) } } \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.\cr DOI-Link: \url{https://doi.org/10.1007/s10543-007-0131-2} } \seealso{ Other polyCub-methods: \code{\link{polyCub.exact.Gauss}}, \code{\link{polyCub.iso}}, \code{\link{polyCub.midpoint}}, \code{\link{polyCub}} } \author{ Sebastian Meyer\cr These R and C implementations of product Gauss cubature are 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}. } \concept{polyCub-methods} \keyword{math} \keyword{spatial} polyCub/man/isScalar.Rd0000644000176200001440000000051613106557311014476 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tools.R \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.Rd0000644000176200001440000000423113357377207016270 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/coerce-sp-methods.R \name{coerce-sp-methods} \alias{coerce-sp-methods} \alias{as.owin.SpatialPolygons} \alias{as.owin.Polygons} \alias{as.owin.Polygon} \alias{coerce,SpatialPolygons,owin-method} \alias{coerce,Polygons,owin-method} \alias{coerce,Polygon,owin-method} \alias{coerce,Polygon,Polygons-method} \title{Coerce \code{"SpatialPolygons"} to \code{"owin"}} \usage{ as.owin.SpatialPolygons(W, ...) as.owin.Polygons(W, ...) as.owin.Polygon(W, ...) } \arguments{ \item{W}{an object of class \code{"SpatialPolygons"}, \code{"Polygons"}, or \code{"Polygon"}.} \item{...}{further arguments passed to \code{\link[spatstat]{owin}}.} } \description{ Package \pkg{polyCub} implements \code{coerce}-methods (\code{as(object, Class)}) to convert \code{"\linkS4class{SpatialPolygons}"} (or \code{"\linkS4class{Polygons}"} or \code{"\linkS4class{Polygon}"}) to \code{"\link[spatstat:owin.object]{owin}"}. They are also available as \code{as.owin.*} functions to support \code{\link{polyCub.midpoint}}. However, these are no registered S3 methods for \code{\link[spatstat]{as.owin}}, since package \pkg{spatstat} is optional. Note that the \pkg{maptools} package contains an alternative implementation of coercion from \code{"SpatialPolygons"} to \code{"owin"} (and reverse), and \R will use the S4 \code{coerce}-method that was loaded last, and prefer the \code{as.owin.SpatialPolygons} S3-method exported from \pkg{maptools} if attached. } \examples{ if (require("spatstat") && require("sp")) { diamond <- list(x = c(1,2,1,0), y = c(1,2,3,2)) # anti-clockwise diamond.owin <- owin(poly = diamond) diamond.sp <- Polygon(lapply(diamond, rev)) # clockwise diamond.owin_from_sp <- as(diamond.sp, "owin") stopifnot(all.equal(diamond.owin, diamond.owin_from_sp)) ## similarly works for Polygons and SpatialPolygons diamond.Ps <- as(diamond.sp, "Polygons") stopifnot(identical(diamond.owin, as.owin(diamond.Ps))) diamond.SpPs <- SpatialPolygons(list(diamond.Ps)) stopifnot(identical(diamond.owin, as.owin(diamond.SpPs))) } } \author{ Sebastian Meyer } \keyword{methods} \keyword{spatial} polyCub/man/isClosed.Rd0000644000176200001440000000066013106557311014502 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tools.R \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}