├── _pkgdown.yml
├── LICENSE
├── data
├── build.rda
├── tmy.RData
├── tmy2.RData
├── boston_block.RData
├── boston_build.RData
├── boston_park.RData
├── beersheva_build.RData
├── beersheva_elev.RData
└── boston_sidewalk.RData
├── tests
├── testthat.R
└── testthat
│ ├── test_shadowFootprint.R
│ ├── test_SVF.R
│ ├── test_shadowHeight.R
│ └── test_radiation.R
├── README-demo1-1.png
├── README-demo1-2.png
├── .gitignore
├── README-abstract.png
├── docs
├── README-demo1-1.png
├── README-demo1-2.png
├── README-abstract.png
├── reference
│ ├── SVF-1.png
│ ├── build-1.png
│ ├── ray-1.png
│ ├── toSeg-1.png
│ ├── Rplot001.png
│ ├── Rplot002.png
│ ├── Rplot003.png
│ ├── shiftAz-1.png
│ ├── classifyAz-1.png
│ ├── coefDirect-1.png
│ ├── coefDirect-2.png
│ ├── inShadow-1.png
│ ├── boston_block-1.png
│ ├── boston_build-1.png
│ ├── boston_park-1.png
│ ├── shadowHeight-1.png
│ ├── surfaceGrid-1.png
│ ├── surfaceGrid-2.png
│ ├── surfaceGrid-3.png
│ ├── beersheva_build-1.png
│ ├── beersheva_elev-1.png
│ ├── boston_sidewalk-1.png
│ ├── shadowFootprint-1.png
│ ├── deg2rad.html
│ ├── rad2deg.html
│ ├── boston_block.html
│ ├── boston_park.html
│ ├── toGMT.html
│ ├── boston_sidewalk.html
│ ├── build.html
│ ├── beersheva_elev.html
│ └── boston_build.html
├── pkgdown.yml
├── link.svg
├── bootstrap-toc.css
├── docsearch.js
├── pkgdown.js
├── bootstrap-toc.js
├── LICENSE-text.html
├── 404.html
└── authors.html
├── data-raw
├── input
│ ├── build.RData
│ ├── tmy.RData
│ ├── tmy2.RData
│ ├── boston_block.RData
│ ├── boston_build.RData
│ ├── boston_park.RData
│ ├── beersheva_build.RData
│ ├── beersheva_elev.RData
│ └── boston_sidewalk.RData
├── vignette
│ └── images
│ │ ├── SVF2.pdf
│ │ ├── shadow_height2b.pdf
│ │ └── shadow_image_rishon.pdf
├── DATASET.R
└── ethis::use_data(build)[201~
├── vignettes
├── introduction2.pdf
└── introduction2.pdf.asis
├── CRAN-RELEASE
├── .Rbuildignore
├── R
├── deg2rad.R
├── rad2deg.R
├── toGMT.R
├── sunLocation.R
├── ray.R
├── shadow-package.R
├── solarpos2.R
├── radiationGrid.R
├── classifyAz.R
├── shiftAz.R
├── toSeg.R
├── plotGrid.R
├── shadowHeightPnt.R
├── checkInputs.R
├── coefDirect.R
├── SVFPnt.R
├── data.R
└── shadowFootprint.R
├── cran-comments.md
├── man
├── deg2rad.Rd
├── rad2deg.Rd
├── boston_park.Rd
├── toGMT.Rd
├── boston_sidewalk.Rd
├── boston_block.Rd
├── build.Rd
├── classifyAz.Rd
├── boston_build.Rd
├── beersheva_elev.Rd
├── shiftAz.Rd
├── beersheva_build.Rd
├── ray.Rd
├── toSeg.Rd
├── tmy.Rd
├── tmy2.Rd
├── solarpos2.Rd
├── shadow.Rd
├── plotGrid.Rd
├── coefDirect.Rd
├── surfaceGrid.Rd
├── shadowFootprint.Rd
├── SVF.Rd
└── shadowHeight.Rd
├── NAMESPACE
├── DESCRIPTION
├── README.md
├── README.Rmd
└── NEWS.md
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2020
2 | COPYRIGHT HOLDER: Michael Dorman
3 |
--------------------------------------------------------------------------------
/data/build.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/build.rda
--------------------------------------------------------------------------------
/data/tmy.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/tmy.RData
--------------------------------------------------------------------------------
/data/tmy2.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/tmy2.RData
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(shadow)
3 |
4 | test_check("shadow")
5 |
--------------------------------------------------------------------------------
/README-demo1-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/README-demo1-1.png
--------------------------------------------------------------------------------
/README-demo1-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/README-demo1-2.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Meta
2 | doc
3 | .Rproj.user
4 | .Rhistory
5 | .RData
6 | .Ruserdata
7 | inst/doc
8 |
--------------------------------------------------------------------------------
/README-abstract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/README-abstract.png
--------------------------------------------------------------------------------
/data/boston_block.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/boston_block.RData
--------------------------------------------------------------------------------
/data/boston_build.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/boston_build.RData
--------------------------------------------------------------------------------
/data/boston_park.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/boston_park.RData
--------------------------------------------------------------------------------
/docs/README-demo1-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/README-demo1-1.png
--------------------------------------------------------------------------------
/docs/README-demo1-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/README-demo1-2.png
--------------------------------------------------------------------------------
/data-raw/input/build.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/build.RData
--------------------------------------------------------------------------------
/data-raw/input/tmy.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/tmy.RData
--------------------------------------------------------------------------------
/data-raw/input/tmy2.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/tmy2.RData
--------------------------------------------------------------------------------
/data/beersheva_build.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/beersheva_build.RData
--------------------------------------------------------------------------------
/data/beersheva_elev.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/beersheva_elev.RData
--------------------------------------------------------------------------------
/data/boston_sidewalk.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data/boston_sidewalk.RData
--------------------------------------------------------------------------------
/docs/README-abstract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/README-abstract.png
--------------------------------------------------------------------------------
/docs/reference/SVF-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/SVF-1.png
--------------------------------------------------------------------------------
/docs/reference/build-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/build-1.png
--------------------------------------------------------------------------------
/docs/reference/ray-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/ray-1.png
--------------------------------------------------------------------------------
/docs/reference/toSeg-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/toSeg-1.png
--------------------------------------------------------------------------------
/docs/reference/Rplot001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/Rplot001.png
--------------------------------------------------------------------------------
/docs/reference/Rplot002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/Rplot002.png
--------------------------------------------------------------------------------
/docs/reference/Rplot003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/Rplot003.png
--------------------------------------------------------------------------------
/docs/reference/shiftAz-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/shiftAz-1.png
--------------------------------------------------------------------------------
/vignettes/introduction2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/vignettes/introduction2.pdf
--------------------------------------------------------------------------------
/docs/reference/classifyAz-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/classifyAz-1.png
--------------------------------------------------------------------------------
/docs/reference/coefDirect-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/coefDirect-1.png
--------------------------------------------------------------------------------
/docs/reference/coefDirect-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/coefDirect-2.png
--------------------------------------------------------------------------------
/docs/reference/inShadow-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/inShadow-1.png
--------------------------------------------------------------------------------
/data-raw/input/boston_block.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/boston_block.RData
--------------------------------------------------------------------------------
/data-raw/input/boston_build.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/boston_build.RData
--------------------------------------------------------------------------------
/data-raw/input/boston_park.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/boston_park.RData
--------------------------------------------------------------------------------
/data-raw/vignette/images/SVF2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/vignette/images/SVF2.pdf
--------------------------------------------------------------------------------
/docs/reference/boston_block-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/boston_block-1.png
--------------------------------------------------------------------------------
/docs/reference/boston_build-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/boston_build-1.png
--------------------------------------------------------------------------------
/docs/reference/boston_park-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/boston_park-1.png
--------------------------------------------------------------------------------
/docs/reference/shadowHeight-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/shadowHeight-1.png
--------------------------------------------------------------------------------
/docs/reference/surfaceGrid-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/surfaceGrid-1.png
--------------------------------------------------------------------------------
/docs/reference/surfaceGrid-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/surfaceGrid-2.png
--------------------------------------------------------------------------------
/docs/reference/surfaceGrid-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/surfaceGrid-3.png
--------------------------------------------------------------------------------
/data-raw/input/beersheva_build.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/beersheva_build.RData
--------------------------------------------------------------------------------
/data-raw/input/beersheva_elev.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/beersheva_elev.RData
--------------------------------------------------------------------------------
/data-raw/input/boston_sidewalk.RData:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/input/boston_sidewalk.RData
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: '2.5'
2 | pkgdown: 1.6.1
3 | pkgdown_sha: ~
4 | articles: {}
5 | last_built: 2020-10-09T19:59Z
6 |
7 |
--------------------------------------------------------------------------------
/docs/reference/beersheva_build-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/beersheva_build-1.png
--------------------------------------------------------------------------------
/docs/reference/beersheva_elev-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/beersheva_elev-1.png
--------------------------------------------------------------------------------
/docs/reference/boston_sidewalk-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/boston_sidewalk-1.png
--------------------------------------------------------------------------------
/docs/reference/shadowFootprint-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/docs/reference/shadowFootprint-1.png
--------------------------------------------------------------------------------
/CRAN-RELEASE:
--------------------------------------------------------------------------------
1 | This package was submitted to CRAN on 2020-12-16.
2 | Once it is accepted, delete this file and tag the release (commit 72eb116).
3 |
--------------------------------------------------------------------------------
/data-raw/vignette/images/shadow_height2b.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/vignette/images/shadow_height2b.pdf
--------------------------------------------------------------------------------
/data-raw/vignette/images/shadow_image_rishon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaeldorman/shadow/HEAD/data-raw/vignette/images/shadow_image_rishon.pdf
--------------------------------------------------------------------------------
/data-raw/DATASET.R:
--------------------------------------------------------------------------------
1 | library(sp)
2 | library(raster)
3 |
4 | # build
5 | load("input/build.RData")
6 | crs(build) = NA
7 | usethis::use_data(build, overwrite = TRUE)
8 |
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^CRAN-RELEASE$
2 | ^Meta$
3 | ^doc$
4 | ^.*\.Rproj$
5 | ^\.Rproj\.user$
6 | ^README\.Rmd$
7 | ^README-.*\.png$
8 | cran-comments.md
9 | README.md
10 | README.Rmd
11 | ^_pkgdown\.yml$
12 | ^docs$
13 | ^pkgdown$
14 | ^data-raw$
15 |
--------------------------------------------------------------------------------
/vignettes/introduction2.pdf.asis:
--------------------------------------------------------------------------------
1 | %\VignetteIndexEntry{R packages: Static PDF and HTML vignettes}
2 | %\VignetteEngine{R.rsp::asis}
3 | %\VignetteKeyword{PDF}
4 | %\VignetteKeyword{HTML}
5 | %\VignetteKeyword{vignette}
6 | %\VignetteKeyword{package}
7 |
--------------------------------------------------------------------------------
/R/deg2rad.R:
--------------------------------------------------------------------------------
1 | #' Degrees to radians
2 | #'
3 | #' @param deg Angle in degrees
4 | #'
5 | #' @return \code{numeric} Angle in radians
6 | #' @export
7 | #'
8 | #' @examples
9 | #' deg2rad(360) == 2*pi
10 |
11 | deg2rad = function(deg) {(deg * pi) / (180)}
12 |
--------------------------------------------------------------------------------
/R/rad2deg.R:
--------------------------------------------------------------------------------
1 | #' Radians to degrees
2 | #'
3 | #' @param rad Angle in radians
4 | #'
5 | #' @return \code{numeric} Angle in degrees
6 | #' @export
7 | #'
8 | #' @examples
9 | #' rad2deg(2*pi) == 360
10 |
11 | rad2deg = function(rad) {(rad * 180) / (pi)}
12 |
--------------------------------------------------------------------------------
/cran-comments.md:
--------------------------------------------------------------------------------
1 | ## Test environments
2 |
3 | * local Ubuntu 20.04 install, R 4.0.3
4 | * win-builder (devel and release)
5 |
6 | ## R CMD check results
7 |
8 | There were no ERRORs or WARNINGs
9 |
10 | ## Downstream dependencies
11 |
12 | None.
13 |
--------------------------------------------------------------------------------
/man/deg2rad.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/deg2rad.R
3 | \name{deg2rad}
4 | \alias{deg2rad}
5 | \title{Degrees to radians}
6 | \usage{
7 | deg2rad(deg)
8 | }
9 | \arguments{
10 | \item{deg}{Angle in degrees}
11 | }
12 | \value{
13 | \code{numeric} Angle in radians
14 | }
15 | \description{
16 | Degrees to radians
17 | }
18 | \examples{
19 | deg2rad(360) == 2*pi
20 | }
21 |
--------------------------------------------------------------------------------
/man/rad2deg.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/rad2deg.R
3 | \name{rad2deg}
4 | \alias{rad2deg}
5 | \title{Radians to degrees}
6 | \usage{
7 | rad2deg(rad)
8 | }
9 | \arguments{
10 | \item{rad}{Angle in radians}
11 | }
12 | \value{
13 | \code{numeric} Angle in degrees
14 | }
15 | \description{
16 | Radians to degrees
17 | }
18 | \examples{
19 | rad2deg(2*pi) == 360
20 | }
21 |
--------------------------------------------------------------------------------
/R/toGMT.R:
--------------------------------------------------------------------------------
1 | #' Local time to GMT
2 | #'
3 | #' The function transforms a \code{POSIXct} object in any given time zone to GMT.
4 | #'
5 | #' @param time Time, a \code{POSIXct} object.
6 | #' @return A a \code{POSIXct} object, in GMT.
7 | #'
8 | #' @examples
9 | #' time = as.POSIXct("1999-01-01 12:00:00", tz = "Asia/Jerusalem")
10 | #' toGMT(time)
11 | #'
12 | #' @export
13 |
14 | toGMT = function(time) {
15 | as.POSIXct(format.POSIXct(time, tz = "GMT"), tz = "GMT")
16 | }
17 |
--------------------------------------------------------------------------------
/man/boston_park.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{boston_park}
5 | \alias{boston_park}
6 | \title{Polygonal layer of a park in Boston}
7 | \format{
8 | A \code{SpatialPolygons} with a single feature.
9 | }
10 | \usage{
11 | boston_park
12 | }
13 | \description{
14 | A \code{SpatialPolygons} object representing the boundaries of a park in Central Boston.
15 | }
16 | \examples{
17 | boston_park
18 | plot(boston_park, axes = TRUE)
19 | }
20 | \keyword{datasets}
21 |
--------------------------------------------------------------------------------
/man/toGMT.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/toGMT.R
3 | \name{toGMT}
4 | \alias{toGMT}
5 | \title{Local time to GMT}
6 | \usage{
7 | toGMT(time)
8 | }
9 | \arguments{
10 | \item{time}{Time, a \code{POSIXct} object.}
11 | }
12 | \value{
13 | A a \code{POSIXct} object, in GMT.
14 | }
15 | \description{
16 | The function transforms a \code{POSIXct} object in any given time zone to GMT.
17 | }
18 | \examples{
19 | time = as.POSIXct("1999-01-01 12:00:00", tz = "Asia/Jerusalem")
20 | toGMT(time)
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/man/boston_sidewalk.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{boston_sidewalk}
5 | \alias{boston_sidewalk}
6 | \title{Polygonal layer of sidewalks in Boston}
7 | \format{
8 | A \code{SpatialLinesDataFrame} with 78 features.
9 | }
10 | \usage{
11 | boston_sidewalk
12 | }
13 | \description{
14 | A \code{SpatialLinesDataFrame} object representing sidewalks in Central Boston.
15 | }
16 | \examples{
17 | boston_sidewalk
18 | plot(boston_sidewalk, axes = TRUE)
19 | }
20 | \keyword{datasets}
21 |
--------------------------------------------------------------------------------
/man/boston_block.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{boston_block}
5 | \alias{boston_block}
6 | \title{Polygonal layer of a building block in Boston}
7 | \format{
8 | A \code{SpatialPolygons} with a single feature.
9 | }
10 | \usage{
11 | boston_block
12 | }
13 | \description{
14 | A \code{SpatialPolygons} object representing the boundaries of a building block in Central Boston.
15 | }
16 | \examples{
17 | boston_block
18 | plot(boston_block, axes = TRUE)
19 | }
20 | \keyword{datasets}
21 |
--------------------------------------------------------------------------------
/man/build.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{build}
5 | \alias{build}
6 | \title{Polygonal layer of four buildings in Rishon}
7 | \format{
8 | A \code{SpatialPolygonsDataFrame} with 4 features and 2 attributes:
9 | \describe{
10 | \item{build_id}{Building ID}
11 | \item{BLDG_HT}{Building height, in meters}
12 | }
13 | }
14 | \usage{
15 | build
16 | }
17 | \description{
18 | A \code{SpatialPolygonsDataFrame} object representing the outlines of four buildings located in Rishon-Le-Zion. The attribute \code{BLDG_HT} contains building height, in meters.
19 | }
20 | \examples{
21 | build
22 | plot(build, axes = TRUE)
23 | }
24 | \keyword{datasets}
25 |
--------------------------------------------------------------------------------
/man/classifyAz.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classifyAz.R
3 | \name{classifyAz}
4 | \alias{classifyAz}
5 | \title{Classify azimuth of line segments}
6 | \usage{
7 | classifyAz(sl)
8 | }
9 | \arguments{
10 | \item{sl}{A \code{SpatialLines*} object}
11 | }
12 | \value{
13 | A \code{numeric} vector with the segment azimuth values (in decimal degrees)
14 | }
15 | \description{
16 | Classify azimuth of line segments
17 | }
18 | \examples{
19 | build_seg = toSeg(build[1, ])
20 | az = classifyAz(build_seg)
21 | plot(build_seg, col = rainbow(4)[cut(az, c(0, 90, 180, 270, 360))])
22 | raster::text(
23 | # rgeos::gCentroid(build_seg, byid = TRUE),
24 | as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(build_seg))), "Spatial"),
25 | round(az)
26 | )
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/tests/testthat/test_shadowFootprint.R:
--------------------------------------------------------------------------------
1 | library(shadow)
2 |
3 | context("shadowFootprint")
4 |
5 | test_that("Shade footprint calculation is correct", {
6 | expect_equal({
7 | data(build)
8 | # location = rgeos::gCentroid(build)
9 | location = as(sf::st_geometry(sf::st_centroid(sf::st_union(sf::st_as_sf(build)))), "Spatial")
10 | time = as.POSIXct("2004-12-24 13:30:00", tz = "Asia/Jerusalem")
11 | solar_pos = suntools::solarpos(
12 | matrix(c(34.7767978098526, 31.9665936050395), ncol = 2),
13 | time
14 | )
15 | footprint = shadowFootprint(
16 | obstacles = build,
17 | obstacles_height_field = "BLDG_HT",
18 | solar_pos = solar_pos
19 | )
20 | # rgeos::gArea(footprint)
21 | sum(sf::st_area(sf::st_as_sf(footprint)))
22 |
23 | },
24 | 6513.44739346873
25 | )
26 | }
27 | )
28 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/man/boston_build.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{boston_build}
5 | \alias{boston_build}
6 | \title{Polygonal layer of three buildings in Boston}
7 | \format{
8 | A \code{SpatialPolygonsDataFrame} with 10 features and 4 attributes:
9 | \describe{
10 | \item{objectid}{Building part ID}
11 | \item{build_id}{Building ID}
12 | \item{part_floor}{Number of floors for part}
13 | \item{height_m}{Building height, in meters}
14 | }
15 | }
16 | \usage{
17 | boston_build
18 | }
19 | \description{
20 | A \code{SpatialPolygonsDataFrame} object representing the outlines of three buildings located in Central Boston. The attribute \code{height_m} contains building height, in meters.
21 | }
22 | \examples{
23 | boston_build
24 | plot(boston_build, axes = TRUE)
25 | }
26 | \keyword{datasets}
27 |
--------------------------------------------------------------------------------
/man/beersheva_elev.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{beersheva_elev}
5 | \alias{beersheva_elev}
6 | \title{DEM of Ramot neighborhood, Beer-Sheva}
7 | \format{
8 | A \code{RasterLayer} representing a grid of 1974 raster cells, each cell is a 30*30 meters rectangle. Data source is the Shuttle Radar Topography Mission (SRTM) 1 Arc-Second Global dataset.
9 | }
10 | \usage{
11 | beersheva_elev
12 | }
13 | \description{
14 | Digital Elevation Model (DEM) of Ramot neighborhood, Beer-Sheva. Raster values represent elevation above sea level, in meters.
15 | }
16 | \examples{
17 | beersheva_elev
18 | plot(beersheva_elev)
19 | }
20 | \references{
21 | \url{https://www.usgs.gov/centers/eros/science/usgs-eros-archive-digital-elevation-shuttle-radar-topography-mission-srtm-1}
22 | }
23 | \keyword{datasets}
24 |
--------------------------------------------------------------------------------
/man/shiftAz.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/shiftAz.R
3 | \name{shiftAz}
4 | \alias{shiftAz}
5 | \title{Shift features by azimuth and distance}
6 | \usage{
7 | shiftAz(object, az, dist)
8 | }
9 | \arguments{
10 | \item{object}{The object to be shifted.}
11 |
12 | \item{az}{Shift azimuth, in decimal degrees.}
13 |
14 | \item{dist}{Shift distance, in \code{object} projection units.}
15 | }
16 | \value{
17 | The shifted \code{object}.
18 | }
19 | \description{
20 | Shift features by azimuth and distance
21 | }
22 | \examples{
23 | s = c(270, 90, 180, 0)
24 | build_shifted = shiftAz(build, az = s, dist = 2.5)
25 | plot(build)
26 | plot(build_shifted, add = TRUE, border = "red")
27 | # raster::text(rgeos::gCentroid(build, byid = TRUE), s)
28 | raster::text(as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(build))), "Spatial"), s)
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/R/sunLocation.R:
--------------------------------------------------------------------------------
1 | # Function to create a 'SpatialPointsDataFrame' object representing sun location
2 |
3 | .sunLocation = function(location, sun_az, sun_elev) {
4 |
5 | # Conditions
6 | stopifnot(class(location) %in% c("SpatialPoints", "SpatialPointsDataFrame"))
7 |
8 | # Average earth-sun distance in meters
9 | dist_m = 149.6 * 10^9
10 |
11 | # To radians
12 | az_rad = deg2rad(90 - sun_az)
13 | sun_elev = deg2rad(sun_elev)
14 |
15 | # Sun height
16 | height = data.frame(height = dist_m * tan(sun_elev))
17 |
18 | # Attribute table
19 | if(is(location, "SpatialPointsDataFrame"))
20 | data = cbind(location@data, height) else
21 | data = height
22 |
23 | # Sun location
24 | sp::SpatialPointsDataFrame(
25 | coords = raster::shift(location, dist_m * cos(az_rad), dist_m * sin(az_rad)),
26 | data = data
27 | )
28 |
29 | }
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/man/beersheva_build.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{beersheva_build}
5 | \alias{beersheva_build}
6 | \title{Polygonal layer of 376 buildings in Beer-Sheva}
7 | \format{
8 | A \code{SpatialPolygonsDataFrame} with 10 features and 4 attributes:
9 | \describe{
10 | \item{build_id}{Building ID}
11 | \item{floors}{Number of floors for building}
12 | \item{apartments}{Number of apartments}
13 | \item{height_m}{Building height, in meters}
14 | \item{elev}{Elevation above sea level of building base, in meters}
15 | }
16 | }
17 | \usage{
18 | beersheva_build
19 | }
20 | \description{
21 | A \code{SpatialPolygonsDataFrame} object representing the outlines of 367 buildings in the Ramot neighborhood, Beer-Sheva. The attribute \code{height_m} contains building height, in meters.
22 | }
23 | \examples{
24 | beersheva_build
25 | plot(beersheva_build, axes = TRUE)
26 | }
27 | \keyword{datasets}
28 |
--------------------------------------------------------------------------------
/man/ray.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ray.R
3 | \name{ray}
4 | \alias{ray}
5 | \title{Line between two points}
6 | \usage{
7 | ray(from, to)
8 | }
9 | \arguments{
10 | \item{from}{A \code{SpatialPoints*} object specifying origin.}
11 |
12 | \item{to}{A \code{SpatialPoints*} object specifying destination.}
13 | }
14 | \value{
15 | A \code{SpatialLines} object.
16 | }
17 | \description{
18 | The function connects two points into a line segment.
19 | }
20 | \examples{
21 | # ctr = rgeos::gCentroid(build)
22 | ctr = as(sf::st_centroid(sf::st_union(sf::st_geometry(sf::st_as_sf(build)))), "Spatial")
23 | angles = seq(0, 359, 20)
24 | sun = mapply(
25 | shadow:::.sunLocation,
26 | sun_az = angles,
27 | MoreArgs = list(
28 | location = ctr,
29 | sun_elev = 10)
30 | )
31 | rays = mapply(ray, MoreArgs = list(from = ctr), to = sun)
32 | rays$makeUniqueIDs = TRUE
33 | rays = do.call(rbind, rays)
34 | plot(rays)
35 | sun = do.call(rbind, sun)
36 | text(sun, as.character(angles))
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/man/toSeg.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/toSeg.R
3 | \name{toSeg}
4 | \alias{toSeg}
5 | \title{Split polygons or lines to segments}
6 | \usage{
7 | toSeg(x)
8 | }
9 | \arguments{
10 | \item{x}{A \code{SpatialLines*} or a \code{SpatialPolygons*} object}
11 | }
12 | \value{
13 | A \code{SpatialLines} object where each segment is represented by a separate feature
14 | }
15 | \description{
16 | Split lines or polygons to separate segments.
17 | }
18 | \examples{
19 | seg = toSeg(build[1, ])
20 | plot(seg, col = sample(rainbow(length(seg))))
21 | # raster::text(rgeos::gCentroid(seg, byid = TRUE), 1:length(seg))
22 | raster::text(as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(seg))), "Spatial"), 1:length(seg))
23 |
24 | # Other data structures
25 | toSeg(geometry(build)) # SpatialPolygons
26 | toSeg(boston_sidewalk) # SpatialLinesDataFrame
27 | toSeg(geometry(boston_sidewalk)) # SpatialLinesDataFrame
28 |
29 | }
30 | \references{
31 | This function uses a modified version of code from the following 'r-sig-geo' post by Roger Bivand:
32 | \url{https://stat.ethz.ch/pipermail/r-sig-geo/2013-April/017998.html}
33 | }
34 |
--------------------------------------------------------------------------------
/man/tmy.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{tmy}
5 | \alias{tmy}
6 | \title{Typical Meteorological Year (TMY) solar radiation in Tel-Aviv}
7 | \format{
8 | A \code{data.frame} with 8760 rows and 7 columns.
9 | }
10 | \usage{
11 | tmy
12 | }
13 | \description{
14 | A table with hourly solar radiation estimates for a typical meteorological year in Tel-Aviv. \itemize{
15 | \item{\code{time} Time, as \code{character} in the \code{"\%Y-\%m-\%d \%H:\%M:\%S"} format, e.g. \code{"2000-01-01 06:00:00"}}, referring to local time
16 | \item{\code{sun_az} Sun azimuth, in decimal degrees from North}
17 | \item{\code{sun_elev} Sun elevation, in decimal degrees}
18 | \item{\code{solar_normal} Direct Normal Irradiance, in Wh/m^2}
19 | \item{\code{solar_diffuse} Diffuse Horizontal Irradiance, in Wh/m^2}
20 | \item{\code{dbt} Dry-bulb temperature, in Celsius degrees}
21 | \item{\code{ws} Wind speed, in m/s}
22 | }
23 | }
24 | \examples{
25 | head(tmy)
26 | }
27 | \references{
28 | \url{https://energyplus.net/weather-location/europe_wmo_region_6/ISR/ISR_Tel.Aviv-Bet.Dagan.401790_MSI}
29 | }
30 | \keyword{datasets}
31 |
--------------------------------------------------------------------------------
/man/tmy2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{tmy2}
5 | \alias{tmy2}
6 | \title{Typical Meteorological Year (TMY) solar radiation in Beer-Sheva}
7 | \format{
8 | A \code{data.frame} with 8760 rows and 7 columns.
9 | }
10 | \usage{
11 | tmy2
12 | }
13 | \description{
14 | A table with hourly solar radiation estimates for a typical meteorological year in Beer-Sheva. \itemize{
15 | \item{\code{time} Time, as \code{character} in the \code{"\%Y-\%m-\%d \%H:\%M:\%S"} format, e.g. \code{"2000-01-01 06:00:00"}}, referring to local time
16 | \item{\code{sun_az} Sun azimuth, in decimal degrees from North}
17 | \item{\code{sun_elev} Sun elevation, in decimal degrees}
18 | \item{\code{solar_normal} Direct Normal Irradiance, in Wh/m^2}
19 | \item{\code{solar_diffuse} Diffuse Horizontal Irradiance, in Wh/m^2}
20 | \item{\code{dbt} Dry-bulb temperature, in Celsius degrees}
21 | \item{\code{ws} Wind speed, in m/s}
22 | }
23 | }
24 | \examples{
25 | head(tmy2)
26 | }
27 | \references{
28 | \url{https://energyplus.net/weather-location/europe_wmo_region_6/ISR/ISR_Beer.Sheva.401900_MSI}
29 | }
30 | \keyword{datasets}
31 |
--------------------------------------------------------------------------------
/man/solarpos2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/solarpos2.R
3 | \name{solarpos2}
4 | \alias{solarpos2}
5 | \title{Calculate solar position(s) for location and time}
6 | \usage{
7 | solarpos2(location, time)
8 | }
9 | \arguments{
10 | \item{location}{A \code{Spatial*} or a \code{Raster} object}
11 |
12 | \item{time}{A \code{SpatialLines*} or a \code{SpatialPolygons*} object}
13 | }
14 | \value{
15 | A \code{matrix} with two columns representing sun position(s); first column is the solar azimuth (in decimal degrees from North), second column is sun elevation (in decimal degrees); rows represent different times corresponding to \code{time}
16 | }
17 | \description{
18 | This is a wrapper function around \code{suntools::solarpos}, adapted for accepting location as a \code{Spatial*} layer or a \code{Raster}. The function calculates layer centroid, transforms it to lon-lat, then calls \code{suntools::solarpos} to calculate solar position(s) for that point at the given time(s)
19 | }
20 | \examples{
21 | time = as.POSIXct("2004-12-24 13:30:00", tz = "Asia/Jerusalem")
22 | proj4string(build) = CRS("EPSG:32636")
23 | solarpos2(build, time)
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(SVF)
4 | export(classifyAz)
5 | export(coefDirect)
6 | export(deg2rad)
7 | export(inShadow)
8 | export(plotGrid)
9 | export(rad2deg)
10 | export(radiation)
11 | export(ray)
12 | export(shadowFootprint)
13 | export(shadowHeight)
14 | export(shiftAz)
15 | export(solarpos2)
16 | export(surfaceGrid)
17 | export(toGMT)
18 | export(toSeg)
19 | exportMethods(SVF)
20 | exportMethods(inShadow)
21 | exportMethods(shadowHeight)
22 | import(raster)
23 | import(sp)
24 | importFrom(methods,"slot<-")
25 | importFrom(methods,as)
26 | importFrom(methods,is)
27 | importFrom(methods,slot)
28 | importFrom(parallel,makeCluster)
29 | importFrom(parallel,mclapply)
30 | importFrom(parallel,parLapply)
31 | importFrom(sf,st_as_sf)
32 | importFrom(sf,st_buffer)
33 | importFrom(sf,st_cast)
34 | importFrom(sf,st_collection_extract)
35 | importFrom(sf,st_convex_hull)
36 | importFrom(sf,st_distance)
37 | importFrom(sf,st_geometry)
38 | importFrom(sf,st_geometry_type)
39 | importFrom(sf,st_intersection)
40 | importFrom(sf,st_intersects)
41 | importFrom(sf,st_length)
42 | importFrom(sf,st_union)
43 | importFrom(suntools,solarpos)
44 | importFrom(utils,setTxtProgressBar)
45 | importFrom(utils,txtProgressBar)
46 |
--------------------------------------------------------------------------------
/man/shadow.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/shadow-package.R
3 | \docType{package}
4 | \name{shadow}
5 | \alias{shadow}
6 | \title{\code{shadow}: R Package for Geometric Shade Calculations}
7 | \description{
8 | Main functions for calculating:\itemize{
9 | \item \code{shadowHeight}, Shadow height at individual points or continuous surface
10 | \item \code{shadowFootprint}, Polygonal layer of shadow footprints on the ground
11 | \item \code{SVF}, Sky View Factor (SVF) value at individual points or continuous surface
12 | }
13 | Typical inputs for these functions include:\itemize{
14 | \item \code{location}, Queried location(s)
15 | \item \code{obstacles}, A polygonal layer of obstacles (e.g. buildings) outline, with height attributes \code{obstacles_height_field}
16 | \item \code{solar_pos}, Solar position (i.e. sun azimuth and elevation angles)
17 | }
18 | The package also provides functions for related preliminary calculations, such as:\itemize{
19 | \item \code{toSeg}, Converting polygons to line segments
20 | \item \code{classifyAz}, Finding segment azimuth
21 | \item \code{shiftAz}, Shifting segments by azimuth and distance
22 | \item \code{ray}, Constructing a line between two points
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/testthat/test_SVF.R:
--------------------------------------------------------------------------------
1 | library(shadow)
2 |
3 | context("SVF")
4 |
5 | test_that("SVF calculation is correct", {
6 | expect_equal({
7 | data(build)
8 | # location0 = rgeos::gCentroid(build)
9 | location0 = as(sf::st_geometry(sf::st_centroid(sf::st_union(sf::st_as_sf(build)))), "Spatial")
10 | SVF(
11 | location = location0,
12 | obstacles = build,
13 | obstacles_height_field = "BLDG_HT"
14 | )
15 | },
16 | 0.39597205126485
17 | )
18 | expect_equal({
19 | data(build)
20 | # location0 = rgeos::gCentroid(build)
21 | location0 = as(sf::st_geometry(sf::st_centroid(sf::st_union(sf::st_as_sf(build)))), "Spatial")
22 | location1 = raster::shift(location0, 0, -15)
23 | SVF(
24 | location = location1,
25 | obstacles = build,
26 | obstacles_height_field = "BLDG_HT"
27 | )
28 | },
29 | 0.139491688314422
30 | )
31 | expect_equal({
32 | data(build)
33 | # location0 = rgeos::gCentroid(build)
34 | location0 = as(sf::st_geometry(sf::st_centroid(sf::st_union(sf::st_as_sf(build)))), "Spatial")
35 | location2 = raster::shift(location0, -10, 20)
36 | SVF(
37 | location = location2,
38 | obstacles = build,
39 | obstacles_height_field = "BLDG_HT"
40 | )
41 | },
42 | 0.770505253636759
43 | )
44 | }
45 | )
46 |
--------------------------------------------------------------------------------
/R/ray.R:
--------------------------------------------------------------------------------
1 | #' Line between two points
2 | #'
3 | #' The function connects two points into a line segment.
4 | #'
5 | #' @param from A \code{SpatialPoints*} object specifying origin.
6 | #' @param to A \code{SpatialPoints*} object specifying destination.
7 | #'
8 | #' @return A \code{SpatialLines} object.
9 | #'
10 | #' @examples
11 | #' # ctr = rgeos::gCentroid(build)
12 | #' ctr = as(sf::st_centroid(sf::st_union(sf::st_geometry(sf::st_as_sf(build)))), "Spatial")
13 | #' angles = seq(0, 359, 20)
14 | #' sun = mapply(
15 | #' shadow:::.sunLocation,
16 | #' sun_az = angles,
17 | #' MoreArgs = list(
18 | #' location = ctr,
19 | #' sun_elev = 10)
20 | #' )
21 | #' rays = mapply(ray, MoreArgs = list(from = ctr), to = sun)
22 | #' rays$makeUniqueIDs = TRUE
23 | #' rays = do.call(rbind, rays)
24 | #' plot(rays)
25 | #' sun = do.call(rbind, sun)
26 | #' text(sun, as.character(angles))
27 | #'
28 | #' @export
29 |
30 | ray = function(from, to) {
31 |
32 | sp::SpatialLines(
33 | list(
34 | sp::Lines(
35 | list(
36 | sp::Line(
37 | rbind(
38 | sp::coordinates(from)[, 1:2],
39 | sp::coordinates(to)[, 1:2]
40 | )
41 | )
42 | ),
43 | ID = "A"
44 | )
45 | ),
46 | proj4string = sp::CRS(sp::proj4string(from))
47 | )
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/man/plotGrid.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/plotGrid.R
3 | \name{plotGrid}
4 | \alias{plotGrid}
5 | \title{Interactive plot for 3D spatial points}
6 | \usage{
7 | plotGrid(grid, color = c("grey", "red")[as.factor(grid$type)], size = 0.2, ...)
8 | }
9 | \arguments{
10 | \item{grid}{A three-dimensional \code{SpatialPoints*} object}
11 |
12 | \item{color}{Point color, either a single value or vector corresponding to the number of points. The default values draws "facade" and "roof" points in different colors, assuming these classes appear in a column named \code{type}, as returned by function \code{\link{surfaceGrid}}}
13 |
14 | \item{size}{Point radius, default is \code{0.1}}
15 |
16 | \item{...}{Additional parameters passed to \code{scatterplot3js}}
17 | }
18 | \value{
19 | An htmlwidget object that is displayed using the object's show or print method. If you don't see your widget plot, try printing it with the print function. (Same as for \code{threejs::scatterplot3js})
20 | }
21 | \description{
22 | This is a wrapper around \code{scatterplot3js} from package \code{threejs}. The function adjusts the x, y and z axes so that 1:1:1 proportion are kept and z=0 corresponds to ground level.
23 | }
24 | \examples{
25 | \dontrun{
26 | grid = surfaceGrid(
27 | obstacles = build,
28 | obstacles_height_field = "BLDG_HT",
29 | res = 1,
30 | offset = 0.01
31 | )
32 | plotGrid(grid)
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/R/shadow-package.R:
--------------------------------------------------------------------------------
1 | #' \code{shadow}: R Package for Geometric Shade Calculations
2 | #'
3 | #' Main functions for calculating:\itemize{
4 | #' \item \code{shadowHeight}, Shadow height at individual points or continuous surface
5 | #' \item \code{shadowFootprint}, Polygonal layer of shadow footprints on the ground
6 | #' \item \code{SVF}, Sky View Factor (SVF) value at individual points or continuous surface
7 | #' }
8 | #' Typical inputs for these functions include:\itemize{
9 | #' \item \code{location}, Queried location(s)
10 | #' \item \code{obstacles}, A polygonal layer of obstacles (e.g. buildings) outline, with height attributes \code{obstacles_height_field}
11 | #' \item \code{solar_pos}, Solar position (i.e. sun azimuth and elevation angles)
12 | #' }
13 | #' The package also provides functions for related preliminary calculations, such as:\itemize{
14 | #' \item \code{toSeg}, Converting polygons to line segments
15 | #' \item \code{classifyAz}, Finding segment azimuth
16 | #' \item \code{shiftAz}, Shifting segments by azimuth and distance
17 | #' \item \code{ray}, Constructing a line between two points
18 | #' }
19 | #'
20 | #' @docType package
21 | #'
22 | #' @name shadow
23 | #'
24 | #' @import sp
25 | #' @import raster
26 | #' @importFrom methods as
27 | #' @importFrom methods is
28 | #' @importFrom utils setTxtProgressBar
29 | #' @importFrom utils txtProgressBar
30 | #' @importFrom parallel mclapply
31 | #' @importFrom parallel makeCluster
32 | #' @importFrom parallel parLapply
33 |
34 | NULL
35 |
--------------------------------------------------------------------------------
/R/solarpos2.R:
--------------------------------------------------------------------------------
1 | #' Calculate solar position(s) for location and time
2 | #'
3 | #' This is a wrapper function around \code{suntools::solarpos}, adapted for accepting location as a \code{Spatial*} layer or a \code{Raster}. The function calculates layer centroid, transforms it to lon-lat, then calls \code{suntools::solarpos} to calculate solar position(s) for that point at the given time(s)
4 | #'
5 | #' @param location A \code{Spatial*} or a \code{Raster} object
6 | #' @param time A \code{SpatialLines*} or a \code{SpatialPolygons*} object
7 | #' @return A \code{matrix} with two columns representing sun position(s); first column is the solar azimuth (in decimal degrees from North), second column is sun elevation (in decimal degrees); rows represent different times corresponding to \code{time}
8 | #'
9 | #' @examples
10 | #' time = as.POSIXct("2004-12-24 13:30:00", tz = "Asia/Jerusalem")
11 | #' proj4string(build) = CRS("EPSG:32636")
12 | #' solarpos2(build, time)
13 | #'
14 | #' @importFrom suntools solarpos
15 | #' @export
16 |
17 | solarpos2 = function(location, time) {
18 |
19 | # Checks
20 | stopifnot(methods::is(location, "Spatial") | methods::is(location, "Raster"))
21 | .checkTime(time)
22 |
23 | if(methods::is(location, "Raster")) location = raster::rasterToPoints(location, spatial = TRUE)
24 |
25 | # Find centroid
26 | # location_ctr = rgeos::gCentroid(location)
27 | location_ctr = sf::st_as_sf(sf::st_centroid(sf::st_union(sf::st_cast(sf::st_geometry(sf::st_as_sf(location), "POINT")))))
28 |
29 | # Transform to lon-lat
30 | location_ctr = sf::st_transform(location_ctr, "OGC:CRS84")
31 |
32 | # Calculate solar position
33 | suntools::solarpos(location_ctr, time)
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: shadow
2 | Type: Package
3 | Title: Geometric Shadow Calculations
4 | Version: 0.7.2
5 | Authors@R: c(
6 | person("Michael", "Dorman", email = "dorman@post.bgu.ac.il", role = c("aut", "cre")),
7 | person("Evyatar", "Erell", email = "erell@bgu.ac.il", role = c("ctb")),
8 | person("Itai", "Kloog", email = "ikloog@gmail.com", role = c("ctb")),
9 | person("Adi", "Vulkan", email = "vulkan@post.bgu.ac.il", role = c("ctb")),
10 | person("Roger", "Bivand", email = "roger.bivand@nhh.no", role = c("ctb")))
11 | Description: Functions for calculating: (1) shadow height, (2) logical shadow flag, (3) shadow footprint, (4) Sky View Factor and (5) radiation load. Basic required inputs include a polygonal layer of obstacle outlines along with their heights (i.e. "extruded polygons"), sun azimuth and sun elevation. The package also provides functions for related preliminary calculations: breaking polygons into line segments, determining azimuth of line segments, shifting segments by azimuth and distance, constructing the footprint of a line-of-sight between an observer and the sun, and creating a 3D grid covering the surface area of extruded polygons.
12 | License: MIT + file LICENSE
13 | LazyData: TRUE
14 | Imports:
15 | raster (>= 2.4-15),
16 | sf (>= 1.0.14),
17 | suntools,
18 | methods,
19 | parallel (>= 3.4.0)
20 | Depends:
21 | R (>= 3.5.0),
22 | sp (>= 2.0.0)
23 | RoxygenNote: 7.2.3
24 | Suggests:
25 | R.rsp,
26 | testthat,
27 | reshape2 (>= 1.4.2),
28 | threejs
29 | VignetteBuilder: R.rsp
30 | URL: https://michaeldorman.github.io/shadow/, https://github.com/michaeldorman/shadow/
31 | BugReports: https://github.com/michaeldorman/shadow/issues/
32 | Encoding: UTF-8
33 |
--------------------------------------------------------------------------------
/R/radiationGrid.R:
--------------------------------------------------------------------------------
1 | .radiationGrid = function(
2 | grid,
3 | obstacles,
4 | obstacles_height_field,
5 | solar_pos,
6 | solar_normal,
7 | solar_diffuse,
8 | returnList,
9 | parallel
10 | ) {
11 |
12 | # Determine shadow
13 | cat("Determining Shadow\n")
14 | s = inShadow(
15 | location = grid,
16 | obstacles = obstacles,
17 | obstacles_height_field = obstacles_height_field,
18 | solar_pos = solar_pos,
19 | parallel = parallel
20 | )
21 | cat("\nDone\n")
22 |
23 | # Calculate 'direct' radiation coefficient
24 | coef = coefDirect(
25 | type = grid$type,
26 | facade_az = grid$facade_az,
27 | solar_pos = solar_pos
28 | )
29 |
30 | # Set coefficient to zero where shaded
31 | coef = coef * !s
32 |
33 | # Multiply by 'direct' radiation load
34 | direct = sweep(
35 | x = coef,
36 | MARGIN = 2,
37 | STATS = solar_normal,
38 | FUN = "*"
39 | )
40 |
41 | # Calculate 'SVF'
42 | cat("Calculating SVF\n")
43 | grid$svf = SVF(
44 | location = grid,
45 | obstacles = obstacles,
46 | obstacles_height_field = obstacles_height_field,
47 | parallel = parallel
48 | )
49 | cat("Done\n")
50 |
51 | # Calculate 'diffuse' radiation
52 | diffuse = outer(grid$svf, solar_diffuse)
53 |
54 | if(returnList) {
55 |
56 | result = list(
57 | direct = direct,
58 | diffuse = diffuse
59 | )
60 |
61 | } else {
62 |
63 | # Sum radiation
64 | direct_sum = rowSums(direct)
65 | diffuse_sum = rowSums(diffuse)
66 | total_sum = direct_sum + diffuse_sum
67 |
68 | # Return result
69 | result = data.frame(
70 | svf = grid$svf,
71 | direct = direct_sum,
72 | diffuse = diffuse_sum,
73 | total = total_sum
74 | )
75 |
76 | }
77 |
78 | return(result)
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/R/classifyAz.R:
--------------------------------------------------------------------------------
1 | #' Classify azimuth of line segments
2 | #'
3 | #' @param sl A \code{SpatialLines*} object
4 | #'
5 | #' @return A \code{numeric} vector with the segment azimuth values (in decimal degrees)
6 | #'
7 | #' @examples
8 | #' build_seg = toSeg(build[1, ])
9 | #' az = classifyAz(build_seg)
10 | #' plot(build_seg, col = rainbow(4)[cut(az, c(0, 90, 180, 270, 360))])
11 | #' raster::text(
12 | #' # rgeos::gCentroid(build_seg, byid = TRUE),
13 | #' as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(build_seg))), "Spatial"),
14 | #' round(az)
15 | #' )
16 | #'
17 | #' @export
18 |
19 | classifyAz = function(sl) {
20 |
21 | # If input is not SpatialLines
22 | stopifnot(class(sl) %in% c("SpatialLines", "SpatialLinesDataFrame"))
23 |
24 | # Empty vector for holding results
25 | result = rep(NA, length(sl))
26 |
27 | # For each feature
28 | for(i in 1:length(sl)) {
29 |
30 | # Select one
31 | s = sl[i, ]
32 | m = s@lines[[1]]@Lines[[1]]@coords
33 |
34 | # If feature is not a segment
35 | if(!nrow(m) == 2)
36 | stop(
37 | "Input contains features which are not segments.
38 | Consider using function 'polToSeg' first."
39 | )
40 |
41 | # Calculate segment direction
42 | x1 = m[1, 1]
43 | y1 = m[1, 2]
44 | x2 = m[2, 1]
45 | y2 = m[2, 2]
46 |
47 | if(x2 >= x1 & y2 > y1) {
48 | az = 360 - (180 / pi) * atan((y2-y1) / (x2-x1))
49 | }
50 | if(x2 >= x1 & y2 <= y1) {
51 | az = (180 / pi) * atan((y1-y2) / (x2-x1))
52 | }
53 | if(x2 < x1 & y2 <= y1) {
54 | az = 180 - (180 / pi) * atan((y1-y2) / (x1-x2))
55 | }
56 | if(x2 < x1 & y2 > y1) {
57 | az = 180 + (180 / pi) * atan((y2-y1) / (x1-x2))
58 | }
59 |
60 | result[i] = az
61 |
62 | }
63 |
64 | return(result)
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/tests/testthat/test_shadowHeight.R:
--------------------------------------------------------------------------------
1 | library(shadow)
2 |
3 | context("shadowHeight")
4 |
5 | test_that("Shade height calculation is correct", {
6 | expect_false(isTRUE(all.equal({
7 | data(build)
8 | # location = rgeos::gCentroid(build)
9 | location = as(sf::st_centroid(sf::st_union(sf::st_geometry(sf::st_as_sf(build)))), "Spatial")
10 | solar_pos = matrix(
11 | c(208.733303840646, 241.006416412884, 262.037856636259,
12 | 28.7994405393304, 1.81958332207186, -34.5606455413366),
13 | ncol = 2)
14 | shadowHeight(
15 | location = location,
16 | obstacles = build,
17 | obstacles_height_field = "BLDG_HT",
18 | solar_pos = solar_pos
19 | )
20 | },
21 | matrix(
22 | c(19.8645079285858, 22.3721120166259, Inf), # Matrix of sun positions
23 | nrow = 1,
24 | ncol = 3
25 | )
26 | )))
27 |
28 | expect_equal({
29 | data(build)
30 | # location = rgeos::gCentroid(build)
31 | location = as(sf::st_centroid(sf::st_union(sf::st_geometry(sf::st_as_sf(build)))), "Spatial")
32 | solar_pos = matrix(c(343.665362102935, -81.0986528138936), ncol = 2)
33 | shadowHeight(
34 | location = location,
35 | obstacles = build,
36 | obstacles_height_field = "BLDG_HT",
37 | solar_pos = solar_pos
38 | )
39 | },
40 | matrix(Inf, nrow = 1, ncol = 1) # Night = Infinite shade height at night
41 | )
42 | expect_equal({
43 | data(build)
44 | # location = rgeos::gCentroid(build)
45 | location = as(sf::st_geometry(sf::st_centroid(sf::st_union(sf::st_as_sf(build)))), "Spatial")
46 | solar_pos = matrix(c(0, 80), ncol = 2)
47 | shadowHeight(
48 | location = location,
49 | obstacles = build,
50 | obstacles_height_field = "BLDG_HT",
51 | solar_pos = solar_pos
52 | )
53 | },
54 | matrix(NA, nrow = 1, ncol = 1) # No shade at noon
55 | )
56 | }
57 | )
58 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 |
6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
7 |
8 | /* All levels of nav */
9 | nav[data-toggle='toc'] .nav > li > a {
10 | display: block;
11 | padding: 4px 20px;
12 | font-size: 13px;
13 | font-weight: 500;
14 | color: #767676;
15 | }
16 | nav[data-toggle='toc'] .nav > li > a:hover,
17 | nav[data-toggle='toc'] .nav > li > a:focus {
18 | padding-left: 19px;
19 | color: #563d7c;
20 | text-decoration: none;
21 | background-color: transparent;
22 | border-left: 1px solid #563d7c;
23 | }
24 | nav[data-toggle='toc'] .nav > .active > a,
25 | nav[data-toggle='toc'] .nav > .active:hover > a,
26 | nav[data-toggle='toc'] .nav > .active:focus > a {
27 | padding-left: 18px;
28 | font-weight: bold;
29 | color: #563d7c;
30 | background-color: transparent;
31 | border-left: 2px solid #563d7c;
32 | }
33 |
34 | /* Nav: second level (shown on .active) */
35 | nav[data-toggle='toc'] .nav .nav {
36 | display: none; /* Hide by default, but at >768px, show it */
37 | padding-bottom: 10px;
38 | }
39 | nav[data-toggle='toc'] .nav .nav > li > a {
40 | padding-top: 1px;
41 | padding-bottom: 1px;
42 | padding-left: 30px;
43 | font-size: 12px;
44 | font-weight: normal;
45 | }
46 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
47 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
48 | padding-left: 29px;
49 | }
50 | nav[data-toggle='toc'] .nav .nav > .active > a,
51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
53 | padding-left: 28px;
54 | font-weight: 500;
55 | }
56 |
57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */
58 | nav[data-toggle='toc'] .nav > .active > ul {
59 | display: block;
60 | }
61 |
--------------------------------------------------------------------------------
/R/shiftAz.R:
--------------------------------------------------------------------------------
1 | #' Shift features by azimuth and distance
2 | #'
3 | #' @param object The object to be shifted.
4 | #' @param az Shift azimuth, in decimal degrees.
5 | #' @param dist Shift distance, in \code{object} projection units.
6 | #'
7 | #' @return The shifted \code{object}.
8 | #'
9 | #' @examples
10 | #' s = c(270, 90, 180, 0)
11 | #' build_shifted = shiftAz(build, az = s, dist = 2.5)
12 | #' plot(build)
13 | #' plot(build_shifted, add = TRUE, border = "red")
14 | #' # raster::text(rgeos::gCentroid(build, byid = TRUE), s)
15 | #' raster::text(as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(build))), "Spatial"), s)
16 | #'
17 | #' @export
18 |
19 | shiftAz = function(object, az, dist) {
20 |
21 | # Check lengths of 'az' and 'dist'
22 | object_features = length(geometry(object))
23 | if(
24 | !(length(az) == 1 | length(az) == object_features)
25 | ) {
26 | stop("'az' needs to be of length 1 or same length as 'object'")
27 | }
28 | if(
29 | !(length(dist) == 1 | length(dist) == object_features)
30 | ) {
31 | stop("'az' needs to be of length 1 or same length as 'object'")
32 | }
33 |
34 | # Recycle if necessary
35 | if(length(az == 1)) az = rep(az, length(object))
36 | if(length(dist == 1)) dist = rep(dist, length(object))
37 |
38 | az_rad = deg2rad(90 - az)
39 |
40 | object_shifted = list()
41 |
42 | for(i in 1:length(object)) {
43 |
44 | object_shifted[[i]] = raster::shift(object[i, ], dist[i] * cos(az_rad[i]), dist[i] * sin(az_rad[i]))
45 |
46 | # Workaround for 'raster::shift' behavior of setting 'coord' dimnames
47 | if(class(object) %in% c("SpatialLines", "SpatialLinesDataFrame")) {
48 | for(j in 1:length(object_shifted[[i]]@lines[[1]]@Lines)) {
49 | dimnames(object_shifted[[i]]@lines[[1]]@Lines[[j]]@coords) = NULL
50 | }
51 | }
52 | if(class(object) %in% c("SpatialPolygons", "SpatialPolygonsDataFrame")) {
53 | for(j in 1:length(object_shifted[[i]]@polygons[[1]]@Polygons)) {
54 | dimnames(object_shifted[[i]]@polygons[[1]]@Polygons[[j]]@coords) = NULL
55 | }
56 | }
57 |
58 | }
59 |
60 | if(class(object) %in% c("SpatialLines", "SpatialLinesDataFrame", "SpatialPolygons", "SpatialPolygonsDataFrame")) {
61 | object_shifted = mapply(spChFIDs, object_shifted, row.names(object))
62 | }
63 |
64 | object_shifted = do.call(rbind, object_shifted)
65 |
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/R/toSeg.R:
--------------------------------------------------------------------------------
1 | #' Split polygons or lines to segments
2 | #'
3 | #' Split lines or polygons to separate segments.
4 | #'
5 | #' @param x A \code{SpatialLines*} or a \code{SpatialPolygons*} object
6 | #' @return A \code{SpatialLines} object where each segment is represented by a separate feature
7 | #'
8 | #' @references
9 | #' This function uses a modified version of code from the following 'r-sig-geo' post by Roger Bivand:
10 | #' \url{https://stat.ethz.ch/pipermail/r-sig-geo/2013-April/017998.html}
11 | #'
12 | #' @examples
13 | #' seg = toSeg(build[1, ])
14 | #' plot(seg, col = sample(rainbow(length(seg))))
15 | #' # raster::text(rgeos::gCentroid(seg, byid = TRUE), 1:length(seg))
16 | #' raster::text(as(sf::st_centroid(sf::st_geometry(sf::st_as_sf(seg))), "Spatial"), 1:length(seg))
17 | #'
18 | #' # Other data structures
19 | #' toSeg(geometry(build)) # SpatialPolygons
20 | #' toSeg(boston_sidewalk) # SpatialLinesDataFrame
21 | #' toSeg(geometry(boston_sidewalk)) # SpatialLinesDataFrame
22 | #'
23 | #' @export
24 |
25 | toSeg = function(x) {
26 |
27 | # Check 'x' class
28 | .checkLinePoly(x)
29 |
30 | seg = list()
31 |
32 | for(f in 1:length(x)) {
33 |
34 | # Select one polygon
35 | dat = x[f, ]
36 |
37 | # Convert to 'SpatialLines' *** Depends on package 'sp' ***
38 | dat_l = as(dat, "SpatialLines")
39 |
40 | # Split to line segments
41 | cSl = sp::coordinates(dat_l)
42 | in_nrows = lapply(cSl, function(x) sapply(x, nrow))
43 | outn = sapply(in_nrows, function(y) sum(y - 1))
44 | res = vector(mode = "list", length = outn)
45 | i = 1
46 | for (j in seq(along=cSl)) {
47 | for (k in seq(along=cSl[[j]])) {
48 | for (l in 1:(nrow(cSl[[j]][[k]])-1)) {
49 | res[[i]] = cSl[[j]][[k]][l:(l+1),]
50 | i = i + 1
51 | }
52 | }
53 | }
54 | res1 = vector(mode = "list", length = outn)
55 | for (i in seq(along = res))
56 | res1[[i]] = sp::Lines(list(sp::Line(res[[i]])), paste(f, i))
57 | seg1 = sp::SpatialLines(res1, proj4string = sp::CRS(sp::proj4string(x)))
58 |
59 | # Add polygon attribute table entry to each segment
60 | if(class(x) %in% c("SpatialLinesDataFrame", "SpatialPolygonsDataFrame")) {
61 | attr_table =
62 | x@data[rep(f, length(seg1)), , drop = FALSE]
63 | rownames(attr_table) = paste(f, 1:length(res))
64 | seg1 = sp::SpatialLinesDataFrame(
65 | seg1,
66 | data = attr_table,
67 | match.ID = FALSE
68 | )
69 | }
70 |
71 | seg[[f]] = seg1
72 |
73 | }
74 |
75 | seg = do.call(rbind, seg)
76 |
77 | seg
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/R/plotGrid.R:
--------------------------------------------------------------------------------
1 | #' Interactive plot for 3D spatial points
2 | #'
3 | #' This is a wrapper around \code{scatterplot3js} from package \code{threejs}. The function adjusts the x, y and z axes so that 1:1:1 proportion are kept and z=0 corresponds to ground level.
4 | #'
5 | #' @param grid A three-dimensional \code{SpatialPoints*} object
6 | #' @param color Point color, either a single value or vector corresponding to the number of points. The default values draws "facade" and "roof" points in different colors, assuming these classes appear in a column named \code{type}, as returned by function \code{\link{surfaceGrid}}
7 | #' @param size Point radius, default is \code{0.1}
8 | #' @param ... Additional parameters passed to \code{scatterplot3js}
9 | #'
10 | #' @return An htmlwidget object that is displayed using the object's show or print method. If you don't see your widget plot, try printing it with the print function. (Same as for \code{threejs::scatterplot3js})
11 | #'
12 | #' @examples
13 | #' \dontrun{
14 | #' grid = surfaceGrid(
15 | #' obstacles = build,
16 | #' obstacles_height_field = "BLDG_HT",
17 | #' res = 1,
18 | #' offset = 0.01
19 | #' )
20 | #' plotGrid(grid)
21 | #' }
22 | #'
23 | #' @export
24 |
25 | plotGrid = function(grid, color = c("grey", "red")[as.factor(grid$type)], size = 0.2, ...) {
26 |
27 | # Check 'threejs' package availability
28 | if(!requireNamespace("threejs"))
29 | stop("You need to install the 'threejs' package to be able to use this function")
30 |
31 | # Check if 'pnt' is '3D point' object
32 | if(!class(grid) %in% c("SpatialPoints", "SpatialPointsDataFrame"))
33 | stop("'grid' is not 'SpatialPoints*'")
34 | if(dimensions(grid) != 3)
35 | stop("'grid' is not three-dimensional")
36 |
37 | # Get 3D point coordinates
38 | coords = coordinates(grid)
39 |
40 | # Determine X, Y and Z range
41 | x_range = range(coords[, 1])
42 | y_range = range(coords[, 2])
43 | z_range = range(coords[, 3])
44 | x_range_diff = diff(x_range)
45 | y_range_diff = diff(y_range)
46 | z_range_diff = diff(z_range)
47 | x_mid = mean(x_range)
48 | y_mid = mean(y_range)
49 | z_mid = mean(z_range)
50 | max_range = max(c(x_range_diff, y_range_diff, z_range_diff))
51 |
52 | # Plot
53 | threejs::scatterplot3js(
54 | x = coords[, 1],
55 | y = coords[, 2],
56 | z = coords[, 3],
57 | xlim = c(x_mid - max_range / 2, x_mid + max_range / 2),
58 | ylim = c(y_mid - max_range / 2, y_mid + max_range / 2),
59 | zlim = c(0, z_mid + max_range),
60 | num.ticks = c(6, 6, 6),
61 | x.ticklabs = rep("", 6),
62 | y.ticklabs = rep("", 6),
63 | color = color,
64 | size = size,
65 | ...
66 | )
67 |
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/data-raw/ethis::use_data(build)[201~:
--------------------------------------------------------------------------------
1 | use_data package:usethis R Documentation
2 |
3 | _C_r_e_a_t_e _p_a_c_k_a_g_e _d_a_t_a
4 |
5 | _D_e_s_c_r_i_p_t_i_o_n:
6 |
7 | ‘use_data()’ makes it easy to save package data in the correct
8 | format. I recommend you save scripts that generate package data in
9 | ‘data-raw’: use ‘use_data_raw()’ to set it up. You also need to
10 | document exported datasets.
11 |
12 | _U_s_a_g_e:
13 |
14 | use_data(
15 | ...,
16 | internal = FALSE,
17 | overwrite = FALSE,
18 | compress = "bzip2",
19 | version = 2
20 | )
21 |
22 | use_data_raw(name = "DATASET", open = rlang::is_interactive())
23 |
24 | _A_r_g_u_m_e_n_t_s:
25 |
26 | ...: Unquoted names of existing objects to save.
27 |
28 | internal: If ‘FALSE’, saves each object in its own ‘.rda’ file in the
29 | data/ directory. These data files bypass the usual export
30 | mechanism and are available whenever the package is loaded
31 | (or via ‘data()’ if ‘LazyData’ is not true).
32 |
33 | If ‘TRUE’, stores all objects in a single ‘R/sysdata.rda’
34 | file. Objects in this file follow the usual export rules.
35 | Note that this means they will be exported if you are using
36 | the common ‘exportPattern()’ rule which exports all objects
37 | except for those that start with ‘.’.
38 |
39 | overwrite: By default, ‘use_data()’ will not overwrite existing files.
40 | If you really want to do so, set this to ‘TRUE’.
41 |
42 | compress: Choose the type of compression used by ‘save()’. Should be
43 | one of "gzip", "bzip2", or "xz".
44 |
45 | version: The serialization format version to use. The default, 2, was
46 | the default format from R 1.4.0 to 3.5.3. Version 3 became
47 | the default from R 3.6.0 and can only be read by R versions
48 | 3.5.0 and higher.
49 |
50 | name: Name of the dataset to be prepared for inclusion in the
51 | package.
52 |
53 | open: Open the newly created file for editing? Happens in RStudio,
54 | if applicable, or via ‘utils::file.edit()’ otherwise.
55 |
56 | _S_e_e _A_l_s_o:
57 |
58 | The data chapter of R Packages.
59 |
60 | _E_x_a_m_p_l_e_s:
61 |
62 | ## Not run:
63 |
64 | x <- 1:10
65 | y <- 1:100
66 |
67 | use_data(x, y) # For external use
68 | use_data(x, y, internal = TRUE) # For internal use
69 | ## End(Not run)
70 |
71 | ## Not run:
72 |
73 | use_data_raw("daisy")
74 | ## End(Not run)
75 |
76 |
77 |
--------------------------------------------------------------------------------
/man/coefDirect.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/coefDirect.R
3 | \name{coefDirect}
4 | \alias{coefDirect}
5 | \title{Coefficient of Direct Normal Irradiance reduction}
6 | \usage{
7 | coefDirect(type, facade_az, solar_pos)
8 | }
9 | \arguments{
10 | \item{type}{\code{character}, specifying surface type. All values must be either \code{"roof"} or \code{"facade"}}
11 |
12 | \item{facade_az}{Facade azimuth, in decimal degrees from North. Only relevant for \code{type="facade"}}
13 |
14 | \item{solar_pos}{A matrix with two columns representing sun position(s); first column is the solar azimuth (in decimal degrees from North), second column is sun elevation (in decimal degrees); rows represent different positions (e.g. at different times of day)}
15 | }
16 | \value{
17 | Numeric vector of coefficients, to be multiplied by the direct beam radiation values. The vector length is the same as the length of the longest input (see \strong{Note} below)
18 | }
19 | \description{
20 | This function calculates the coefficient of reduction in Direct Normal Irradiance load due to angle of incidence. For example, a coefficient of 1 is obtained when the sun is perpendicular to the surface.
21 | }
22 | \note{
23 | All four arguments are recycled to match each other's length. For example, you may specify a single \code{type} value of \code{"roof"} or \code{"facade"} and a single \code{facade_az} value, but multiple \code{sun_az} and \code{sun_elev} values, for calculating the coefficients for a single location given different positions of the sun, etc.
24 | }
25 | \examples{
26 | # Basic usage
27 | coefDirect(type = "facade", facade_az = 180, solar_pos = matrix(c(210, 30), ncol = 2))
28 |
29 | # Demonstration - Direct beam radiation coefficient on 'facades'
30 | sun_az = seq(270, 90, by = -5)
31 | sun_elev = seq(0, 90, by = 5)
32 | solar_pos = expand.grid(sun_az = sun_az, sun_elev = sun_elev)
33 | solar_pos$coef = coefDirect(type = "facade", facade_az = 180, solar_pos = as.matrix(solar_pos))[1, ]
34 | coef = reshape2::acast(solar_pos, sun_az ~ sun_elev, value.var = "coef")
35 | image(
36 | 180 - sun_az, sun_elev, coef,
37 | col = rev(heat.colors(10)),
38 | breaks = seq(0, 1, 0.1),
39 | asp = 1,
40 | xlab = "Facade azimuth - Sun azimuth (deg)",
41 | ylab = "Sun elevation (deg)",
42 | main = "Facade - Coefficient of Direct Normal Irradiance"
43 | )
44 | contour(180 - sun_az, sun_elev, coef, add = TRUE)
45 |
46 | # Demonstration - Direct beam radiation coefficient on 'roofs'
47 | solar_pos$coef = coefDirect(type = "roof", facade_az = 180, solar_pos = as.matrix(solar_pos))[1, ]
48 | coef = reshape2::acast(solar_pos, sun_az ~ sun_elev, value.var = "coef")
49 | image(
50 | 180 - sun_az, sun_elev, coef,
51 | col = rev(heat.colors(10)),
52 | breaks = seq(0, 1, 0.1),
53 | asp = 1,
54 | xlab = "Facade azimuth - Sun azimuth (deg)",
55 | ylab = "Sun elevation (deg)",
56 | main = "Roof - Coefficient of Direct Normal Irradiance"
57 | )
58 | contour(180 - sun_az, sun_elev, coef, add = TRUE)
59 | }
60 |
--------------------------------------------------------------------------------
/man/surfaceGrid.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/surfaceGrid.R
3 | \name{surfaceGrid}
4 | \alias{surfaceGrid}
5 | \title{Create grid of 3D points covering the 'facades' and 'roofs' of obstacles}
6 | \usage{
7 | surfaceGrid(obstacles, obstacles_height_field, res, offset = 0.01)
8 | }
9 | \arguments{
10 | \item{obstacles}{A \code{SpatialPolygonsDataFrame} object specifying the obstacles outline}
11 |
12 | \item{obstacles_height_field}{Name of attribute in \code{obstacles} with extrusion height for each feature}
13 |
14 | \item{res}{Required grid resolution, in CRS units}
15 |
16 | \item{offset}{Offset between grid points and facade (horizontal distance) or between grid points and roof (vertical distance).}
17 | }
18 | \value{
19 | A 3D \code{SpatialPointsDataFrame} layer, including all attributes of the original obstacles each surface point corresponds to, followed by six new attributes:\itemize{
20 | \item{\code{obs_id} Unique consecutive ID for each feature in \code{obstacles}}
21 | \item{\code{type} Either \code{"facade"} or \code{"roof"}}
22 | \item{\code{seg_id} Unique consecutive ID for each facade segment (only for 'facade' points)}
23 | \item{\code{xy_id} Unique consecutive ID for each ground location (only for 'facade' points)}
24 | \item{\code{facade_az} The azimuth of the corresponding facade, in decimal degrees (only for 'facade' points)}
25 | }
26 | }
27 | \description{
28 | The function creates a grid of 3D points covering the given obstacles at specified resolution. Such a grid can later on be used to quantify the shaded / non-shaded proportion of the obstacles surface area.
29 | }
30 | \note{
31 | The reason for introducing an offset is to avoid ambiguity as for whether the grid points are "inside" or "outside" of the obstacle. With an offset all grid points are "outside" of the building and thus not intersecting it. \code{offset} should be given in CRS units; default is 0.01.
32 | }
33 | \examples{
34 | grid = surfaceGrid(
35 | obstacles = build,
36 | obstacles_height_field = "BLDG_HT",
37 | res = 2
38 | )
39 | plot(grid)
40 | plot(grid, pch = 1, lwd = 0.1, col = "black", add = TRUE)
41 |
42 | # When 'res/2' is larger then height, facade will be left unsampled
43 | build_small = build
44 | build_small$BLDG_HT = 1
45 | grid = surfaceGrid(
46 | obstacles = build_small,
47 | obstacles_height_field = "BLDG_HT",
48 | res = 2
49 | )
50 | plot(grid)
51 | plot(grid, pch = 1, lwd = 0.1, col = "black", add = TRUE)
52 | table(grid$type)
53 |
54 | grid = surfaceGrid(
55 | obstacles = build_small,
56 | obstacles_height_field = "BLDG_HT",
57 | res = 2.00001 # res/2 > h
58 | )
59 | plot(grid)
60 | plot(grid, pch = 1, lwd = 0.1, col = "black", add = TRUE)
61 | table(grid$type)
62 |
63 | # When input already contains 'obs_id', 'type', 'seg_id', 'xy_id', 'facade_az' or 'ZZZ'
64 | build2 = build
65 | build2$ZZZ = 1
66 | grid = surfaceGrid(
67 | obstacles = build2,
68 | obstacles_height_field = "BLDG_HT",
69 | res = 2
70 | )
71 |
72 | }
73 | \seealso{
74 | Function \code{\link{plotGrid}} to visualize grid.
75 | }
76 |
--------------------------------------------------------------------------------
/tests/testthat/test_radiation.R:
--------------------------------------------------------------------------------
1 | library(shadow)
2 |
3 | context("radiation")
4 |
5 | test_that("radiation calculation is incorrect", {
6 | expect_false(isTRUE(all.equal({
7 |
8 | data(build)
9 | this_CRS = slot(build, "proj4string")
10 | data(tmy)
11 |
12 | # grid
13 | set.seed(17)
14 | grid = new(
15 | "SpatialPointsDataFrame",
16 | data = structure(
17 | list(
18 | build_id = c("407", "407", "407"),
19 | BLDG_HT = c(21.38,
20 | 21.38, 21.38),
21 | obs_id = c(1L, 1L, 1L),
22 | type = c("facade", "roof",
23 | "facade"),
24 | seg_id = c(6L, NA, 21L),
25 | xy_id = c(18L, NA, 50L),
26 | facade_az = c(321.427363755109, NA, 136.951204869441)
27 | ),
28 | .Names = c(
29 | "build_id",
30 | "BLDG_HT",
31 | "obs_id",
32 | "type",
33 | "seg_id",
34 | "xy_id",
35 | "facade_az"
36 | ),
37 | row.names = c(400L, 15L, 687L),
38 | class = "data.frame"
39 | )
40 | ,
41 | coords.nrs = numeric(0)
42 | ,
43 | coords = structure(
44 | c(
45 | 667855.102115946,
46 | 667862.288856074,
47 | 667871.369943073,
48 | 3538112.62815535,
49 | 3538101.47268511,
50 | 3538095.63665798,
51 | 11,
52 | 21.39,
53 | 21
54 | ),
55 | .Dim = c(3L, 3L),
56 | .Dimnames = list(NULL, c("x1", "x2", "h"))
57 | )
58 | ,
59 | bbox = structure(
60 | c(
61 | 667855.102115946,
62 | 3538095.63665798,
63 | 11,
64 | 667871.369943073,
65 | 3538112.62815535,
66 | 21.39
67 | ),
68 | .Dim = c(3L, 2L),
69 | .Dimnames = list(c("x1", "x2", "h"), c("min", "max"))
70 | )
71 | ,
72 | proj4string = this_CRS # new("CRS", projargs = "+proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0")
73 | )
74 |
75 | solar_pos = tmy[, c("sun_az", "sun_elev")]
76 | solar_pos = as.matrix(solar_pos)
77 |
78 | radiation(
79 | grid = grid,
80 | obstacles = build,
81 | obstacles_height_field = "BLDG_HT",
82 | solar_pos = solar_pos[8:17, , drop = FALSE],
83 | solar_normal = tmy$solar_normal[8:17],
84 | solar_diffuse = tmy$solar_diffuse[8:17]
85 | )
86 | },
87 |
88 | structure(
89 | list(
90 | svf = c(0.484475008535678, 0.998328963274761,0.491760588247644),
91 | direct = c(21.0822885075299, 2755.36321510678,2913.69184551694),
92 | diffuse = c(250.473579412946, 516.136074013052,254.240224124032),
93 | total = c(271.555867920476, 3271.49928911984,3167.93206964097)
94 | ),
95 | .Names = c("svf", "direct", "diffuse", "total"),
96 | row.names = c(NA,-3L),
97 | class = "data.frame"
98 | )
99 |
100 | )))
101 |
102 | }
103 | )
104 |
--------------------------------------------------------------------------------
/man/shadowFootprint.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/shadowFootprint.R
3 | \name{shadowFootprint}
4 | \alias{shadowFootprint}
5 | \alias{shadowFootprint,SpatialPolygonsDataFrame-method}
6 | \title{Shadow footprint on the ground}
7 | \usage{
8 | \S4method{shadowFootprint}{SpatialPolygonsDataFrame}(
9 | obstacles,
10 | obstacles_height_field,
11 | solar_pos = solarpos2(obstacles, time),
12 | time = NULL,
13 | b = 0.01
14 | )
15 | }
16 | \arguments{
17 | \item{obstacles}{A \code{SpatialPolygonsDataFrame} object specifying the obstacles outline}
18 |
19 | \item{obstacles_height_field}{Name of attribute in \code{obstacles} with extrusion height for each feature}
20 |
21 | \item{solar_pos}{A \code{matrix} with one row and two columns; first column is the solar azimuth (in decimal degrees from North), second column is sun elevation (in decimal degrees)}
22 |
23 | \item{time}{When \code{solar_pos} is unspecified, \code{time} can be passed to automatically calculate \code{solar_pos} based on the time and the centroid of \code{obstacles}, using function \code{suntools::solarpos}. In such case \code{obstacles} must have a defined CRS (not \code{NA}). The \code{time} value must be a \code{POSIXct} or \code{POSIXlt} object}
24 |
25 | \item{b}{Buffer size for shadow footprints of individual segments of a given polygon; used to eliminate minor internal holes in the resulting shadow polygon.}
26 | }
27 | \value{
28 | A \code{SpatialPolygonsDataFrame} object representing shadow footprint, plus buildings outline. Object length is the same as that of the input \code{obstacles}, with an individual footprint feature for each obstacle.
29 | }
30 | \description{
31 | Creates a polygonal layer of shadow footprints on the ground, taking into account:\itemize{
32 | \item{Obstacles outline (\code{obstacles}), given by a polygonal layer with a height attribute (\code{obstacles_height_field})}
33 | \item{Sun position (\code{solar_pos}), given by azimuth and elevation angles}
34 | }
35 | The calculation method was inspired by Morel Weisthal's MSc thesis at the Ben-Gurion University of the Negev.
36 | }
37 | \examples{
38 | time = as.POSIXct("2004-12-24 13:30:00", tz = "Asia/Jerusalem")
39 | proj4string(build) = CRS("EPSG:32636")
40 | location_geo = matrix(c(34.7767978098526, 31.9665936050395), ncol = 2)
41 | solar_pos = suntools::solarpos(location_geo, time)
42 | footprint1 = ## Using 'solar_pos'
43 | shadowFootprint(
44 | obstacles = build,
45 | obstacles_height_field = "BLDG_HT",
46 | solar_pos = solar_pos
47 | )
48 | footprint2 = ## Using 'time'
49 | shadowFootprint(
50 | obstacles = build,
51 | obstacles_height_field = "BLDG_HT",
52 | time = time
53 | )
54 | all.equal(footprint1, footprint2)
55 | footprint = footprint1
56 | plot(footprint, col = adjustcolor("lightgrey", alpha.f = 0.5))
57 | plot(build, add = TRUE, col = "darkgrey")
58 |
59 | }
60 | \references{
61 | Weisthal, M. (2014). Assessment of potential energy savings in Israel through climate-aware residential building design (MSc Thesis, Ben-Gurion University of the Negev).
62 | \url{https://www.dropbox.com/s/bztnh1fi9znmswj/Thesis_Morel_Weisthal.pdf?dl=1}
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [](https://cran.r-project.org/package=shadow)
5 | [](https://cran.r-project.org/package=shadow)
6 |
7 | ### Introduction
8 |
9 | `shadow` is an R package for geometric shadow calculations in an urban
10 | environment. A detailed description can be found in the [R Journal paper
11 | (2019)](https://journal.r-project.org/archive/2019/RJ-2019-024/RJ-2019-024.pdf):
12 |
13 | [](https://journal.r-project.org/archive/2019/RJ-2019-024/RJ-2019-024.pdf)
14 |
15 | ### Installation
16 |
17 | CRAN version:
18 |
19 | ``` r
20 | install.packages("shadow")
21 | ```
22 |
23 | GitHub version:
24 |
25 | ``` r
26 | install.packages("remotes")
27 | remotes::install_github("michaeldorman/shadow")
28 | ```
29 |
30 | ## Documentation
31 |
32 | The complete documentation can be found at
33 |
YEAR: 2020 117 | COPYRIGHT HOLDER: Michael Dorman 118 |119 | 120 |
R/data.R
116 | boston_block.RdA SpatialPolygons object representing the boundaries of a building block in Central Boston.
boston_block
124 |
125 |
126 | A SpatialPolygons with a single feature.
137 |boston_block 132 |#> class : SpatialPolygons 133 | #> features : 1 134 | #> extent : 328903.9, 329144.9, 4690539, 4690799 (xmin, xmax, ymin, ymax) 135 | #> crs : +proj=utm +zone=19 +datum=WGS84 +units=m +no_defs
A SpatialPolygons object representing the boundaries of a park in Central Boston.
boston_park
124 |
125 |
126 | A SpatialPolygons with a single feature.
140 |boston_park 132 |#> class : SpatialPolygonsDataFrame 133 | #> features : 1 134 | #> extent : 328920.9, 329072.8, 4690670, 4690782 (xmin, xmax, ymin, ymax) 135 | #> crs : +proj=utm +zone=19 +datum=WGS84 +units=m +no_defs 136 | #> variables : 1 137 | #> names : objectid 138 | #> value : 46
The function transforms a POSIXct object in any given time zone to GMT.
toGMT(time)124 | 125 |
| time | 130 |Time, a |
131 |
|---|
A a POSIXct object, in GMT.
143 |#> [1] "1999-01-01 10:00:00 GMT"142 |
A SpatialLinesDataFrame object representing sidewalks in Central Boston.
boston_sidewalk
124 |
125 |
126 | A SpatialLinesDataFrame with 78 features.
141 |boston_sidewalk 132 |#> class : SpatialLinesDataFrame 133 | #> features : 78 134 | #> extent : 328900, 329148, 4690530, 4690805 (xmin, xmax, ymin, ymax) 135 | #> crs : +proj=utm +zone=19 +datum=WGS84 +units=m +no_defs 136 | #> variables : 3 137 | #> names : OBJECTID, TYPE, ShapeSTLen 138 | #> min values : 100131, CWALK-CL, 1.60299290715796 139 | #> max values : 99792, SWALK-CL, 314.796524738377
A SpatialPolygonsDataFrame object representing the outlines of four buildings located in Rishon-Le-Zion. The attribute BLDG_HT contains building height, in meters.
build
124 |
125 |
126 | A SpatialPolygonsDataFrame with 4 features and 2 attributes:
Building ID
Building height, in meters
146 |build 137 |#> class : SpatialPolygonsDataFrame 138 | #> features : 4 139 | #> extent : 667850.3, 667941.1, 3538084, 3538143 (xmin, xmax, ymin, ymax) 140 | #> crs : NA 141 | #> variables : 2 142 | #> names : build_id, BLDG_HT 143 | #> min values : 365, 19.07 144 | #> max values : 831, 22.73
Digital Elevation Model (DEM) of Ramot neighborhood, Beer-Sheva. Raster values represent elevation above sea level, in meters.
121 |beersheva_elev
124 |
125 |
126 | A RasterLayer representing a grid of 1974 raster cells, each cell is a 30*30 meters rectangle. Data source is the Shuttle Radar Topography Mission (SRTM) 1 Arc-Second Global dataset.
https://lta.cr.usgs.gov/SRTM1Arc
132 | 133 |145 |beersheva_elev 135 |#> class : RasterLayer 136 | #> dimensions : 47, 42, 1974 (nrow, ncol, ncell) 137 | #> resolution : 30, 30 (x, y) 138 | #> extent : 670636.6, 671896.6, 3461431, 3462841 (xmin, xmax, ymin, ymax) 139 | #> crs : +proj=utm +zone=36 +datum=WGS84 +units=m +no_defs 140 | #> source : memory 141 | #> names : elev_m 142 | #> values : 283.2574, 356.0146 (min, max) 143 | #>
R/data.R
116 | boston_build.RdA SpatialPolygonsDataFrame object representing the outlines of three buildings located in Central Boston. The attribute height_m contains building height, in meters.
boston_build
124 |
125 |
126 | A SpatialPolygonsDataFrame with 10 features and 4 attributes:
Building part ID
Building ID
Number of floors for part
Building height, in meters
148 |boston_build 139 |#> class : SpatialPolygonsDataFrame 140 | #> features : 10 141 | #> extent : 328949.6, 329130.9, 4690552, 4690772 (xmin, xmax, ymin, ymax) 142 | #> crs : +proj=utm +zone=19 +datum=WGS84 +units=m +no_defs 143 | #> variables : 4 144 | #> names : objectid, build_id, part_floor, height_m 145 | #> min values : 99167, 1, 1, 3.631387178664 146 | #> max values : 123842, 3, 8, 240.240312