From 4bbf8ce38b0637829920ab4a6ea9d34471e03505 Mon Sep 17 00:00:00 2001 From: pegeler <32426645+pegeler@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:46:51 -0500 Subject: [PATCH] updating examples and docs for get_haversine_distance and read_gpx --- R/package/DESCRIPTION | 2 +- R/package/NEWS.md | 25 +++++++---- R/package/R/RcppExports.R | 4 +- R/package/R/gpx.r | 60 ++++++++++++++----------- R/package/man/get_haversine_distance.Rd | 56 +++++++++++++---------- R/package/man/read_gpx.Rd | 2 +- R/package/src/RcppExports.cpp | 10 ++--- R/package/src/haversine.cpp | 8 ++-- R/package/tests/testthat/test-gpx.r | 26 +++++------ 9 files changed, 108 insertions(+), 85 deletions(-) diff --git a/R/package/DESCRIPTION b/R/package/DESCRIPTION index fa3139b..0966107 100644 --- a/R/package/DESCRIPTION +++ b/R/package/DESCRIPTION @@ -1,6 +1,6 @@ Package: eddington Title: Compute a Cyclist's Eddington Number -Version: 4.1.1 +Version: 4.1.2 Authors@R: c( person('Paul', 'Egeler', email = 'paulegeler@gmail.com', role = c('aut','cre')), person('Tashi', 'Reigle', role = 'ctb')) diff --git a/R/package/NEWS.md b/R/package/NEWS.md index 11ca68c..f173fc9 100644 --- a/R/package/NEWS.md +++ b/R/package/NEWS.md @@ -1,8 +1,15 @@ +# eddington 4.1.2 (Release date: 2023-12-12) + +Changes: + +- Enhanced and fixed typos in examples. +- Changed API to `get_haversine_distance()`. + # eddington 4.1.1 (Release date: 2023-12-11) Changes: -- Adding examples for `read_gpx` and `get_haversine_distance`. +- Adding examples for `read_gpx()` and `get_haversine_distance()`. # eddington 4.1.0 (Release date: 2023-11-24) @@ -18,11 +25,11 @@ Changes: - Minimum R version is now 4.3.0 and requires compiler capable of C++17 standard. - Full re-implementation of C++ code. As a result, memory usage will be reduced for typical datasets. -- Introduction of `EddingtonModule` Rcpp module. This class maintains algorithm +- Introduction of `EddingtonModule()` Rcpp module. This class maintains algorithm state, and so can be updated multiple times as new data comes in. -- Introduction of `Eddington` R6 class. This provides similar functionality to - the `EddingtonModule` Rcpp module. All methods are implemented in pure R. It - uses R's new `hashtab` data structure, which is experimental as of this +- Introduction of `Eddington()` R6 class. This provides similar functionality to + the `EddingtonModule()` Rcpp module. All methods are implemented in pure R. It + uses R's new `hashtab()` data structure, which is experimental as of this package release. # eddington 2.1.2 (Release date: 2020-03-24) @@ -58,9 +65,9 @@ Changes: Changes: - R version of `Eddington_number` and c++ `E_fast` are now defunct. -- `E_num` is now the method for getting the single maximum Eddington number of a dataset. -- Added `E_sat` that checks to see if a dataset satisfies a certain Eddington number. -- Added `E_req` that determines the minimum number of rides to increment Eddington number. +- `E_num()` is now the method for getting the single maximum Eddington number of a dataset. +- Added `E_sat()` that checks to see if a dataset satisfies a certain Eddington number. +- Added `E_req()` that determines the minimum number of rides to increment Eddington number. # eddington 0.1.1 (Release date: 2018-12-15) @@ -72,7 +79,7 @@ Changes: Changes: -- Added cumulative function, `E_cum`. +- Added cumulative function, `E_cum()`. # eddington 0.0.0 (Release date: 2018-11-27) diff --git a/R/package/R/RcppExports.R b/R/package/R/RcppExports.R index 950f9aa..c98b583 100644 --- a/R/package/R/RcppExports.R +++ b/R/package/R/RcppExports.R @@ -70,8 +70,8 @@ E_next <- function(rides) { .Call(`_eddington_E_next`, rides) } -get_haversine_distance_ <- function(lat_1, long_1, lat_2, long_2, r) { - .Call(`_eddington_get_haversine_distance_`, lat_1, long_1, lat_2, long_2, r) +get_haversine_distance_ <- function(lat_1, lon_1, lat_2, lon_2, r) { + .Call(`_eddington_get_haversine_distance_`, lat_1, lon_1, lat_2, lon_2, r) } # Register entry points for exported C++ functions diff --git a/R/package/R/gpx.r b/R/package/R/gpx.r index 603062b..d6cc740 100644 --- a/R/package/R/gpx.r +++ b/R/package/R/gpx.r @@ -6,53 +6,61 @@ TIMESTAMP_FORMAT <- "%FT%T.000Z" #' Uses the Haversine great-circle distance formula to compute the distance #' between two latitude/longitude points. #' -#' @param lat_1,long_1,lat_2,long_2 The coordinates +#' @param lat_1,lon_1,lat_2,lon_2 The coordinates #' used to compute the distance. #' @param units The units of the output distance. #' @examples -#' # In NYC, 20 blocks == 1 mile. Thus, computing the distance of two points along -#' # 7th Ave from W 39 St to W 59 St should return ~1 mile. -#' w39_coords <- list(lat=40.75406905512651, long=-73.98830604245481) -#' w59_coords <- list(lat=40.76684156255418, long=-73.97908243833855) +#' # In NYC, 20 blocks == 1 mile. Thus, computing the distance between two +#' # points along 7th Ave from W 39 St to W 59 St should return ~1 mile. +#' w39_coords <- list(lat=40.75406905512651, lon=-73.98830604245481) +#' w59_coords <- list(lat=40.76684156255418, lon=-73.97908243833855) #' #' get_haversine_distance( #' w39_coords$lat, -#' w39_coords$long, +#' w39_coords$lon, #' w59_coords$lat, -#' w59_coords$long, +#' w59_coords$lon, #' "miles" #' ) #' -#' # The combined distance of multiple points on a track can be computed as well. +#' # The total distance along a sequence of points can be computed. Consider the +#' # following sequence of points along Park Ave in the form of a list of points +#' # where each point is a list containing a `lat` and `lon` tag. #' park_ave_coords <- list( -#' list(lat=40.735337983655434, long=-73.98973648773142), # E 15 St / Park Ave -#' list(lat=40.74772623378332, long=-73.98066078090876), # E 35 St / Park Ave -#' list(lat=40.76026319186414, long=-73.97149360922498), # E 55 St / Park Ave -#' list(lat=40.77301604875587, long=-73.96217737679450) # E 75 St / Park Ave +#' list(lat=40.735337983655434, lon=-73.98973648773142), # E 15 St +#' list(lat=40.74772623378332, lon=-73.98066078090876), # E 35 St +#' list(lat=40.76026319186414, lon=-73.97149360922498), # E 55 St +#' list(lat=40.77301604875587, lon=-73.96217737679450) # E 75 St #' ) #' -#' sum( -#' sapply( -#' seq_along(park_ave_coords)[-1], -#' \(i) get_haversine_distance( -#' park_ave_coords[[i]]$lat, -#' park_ave_coords[[i]]$long, -#' park_ave_coords[[i - 1]]$lat, -#' park_ave_coords[[i - 1]]$long, -#' "miles" +#' # We can create a function to compute the total distance as follows: +#' compute_total_distance <- function(coords) { +#' sum( +#' sapply( +#' seq_along(coords)[-1], +#' \(i) get_haversine_distance( +#' coords[[i]]$lat, +#' coords[[i]]$lon, +#' coords[[i - 1]]$lat, +#' coords[[i - 1]]$lon, +#' "miles" +#' ) #' ) #' ) -#' ) +#' } +#' +#' # Then applying the function to our sequence results in a total distance. +#' compute_total_distance(park_ave_coords) #' @returns The distance between two points in the requested units. #' @references #' @export get_haversine_distance <- function(lat_1, - long_1, + lon_1, lat_2, - long_2, + lon_2, units = c("miles", "kilometers")) { r <- switch(match.arg(units), miles = R_E_MI, kilometers = R_E_KM) - .Call(`_eddington_get_haversine_distance_`, lat_1, long_1, lat_2, long_2, r) + .Call(`_eddington_get_haversine_distance_`, lat_1, lon_1, lat_2, lon_2, r) } #' Read a GPX file into a data frame containing dates and distances @@ -82,7 +90,7 @@ get_haversine_distance <- function(lat_1, #' ) #' #' # Read in all files and combine them into a single data frame -#' rides <- do.call(rbind, lapply(activity_files, read_gpx)) +#' rides <- do.call(rbind, lapply(gpx_export_files, read_gpx)) #' } #' @returns A data frame containing up to two columns: #' \describe{ diff --git a/R/package/man/get_haversine_distance.Rd b/R/package/man/get_haversine_distance.Rd index 7473694..afc9e62 100644 --- a/R/package/man/get_haversine_distance.Rd +++ b/R/package/man/get_haversine_distance.Rd @@ -6,14 +6,14 @@ \usage{ get_haversine_distance( lat_1, - long_1, + lon_1, lat_2, - long_2, + lon_2, units = c("miles", "kilometers") ) } \arguments{ -\item{lat_1, long_1, lat_2, long_2}{The coordinates +\item{lat_1, lon_1, lat_2, lon_2}{The coordinates used to compute the distance.} \item{units}{The units of the output distance.} @@ -26,39 +26,47 @@ Uses the Haversine great-circle distance formula to compute the distance between two latitude/longitude points. } \examples{ -# In NYC, 20 blocks == 1 mile. Thus, computing the distance of two points along -# 7th Ave from W 39 St to W 59 St should return ~1 mile. -w39_coords <- list(lat=40.75406905512651, long=-73.98830604245481) -w59_coords <- list(lat=40.76684156255418, long=-73.97908243833855) +# In NYC, 20 blocks == 1 mile. Thus, computing the distance between two +# points along 7th Ave from W 39 St to W 59 St should return ~1 mile. +w39_coords <- list(lat=40.75406905512651, lon=-73.98830604245481) +w59_coords <- list(lat=40.76684156255418, lon=-73.97908243833855) get_haversine_distance( w39_coords$lat, - w39_coords$long, + w39_coords$lon, w59_coords$lat, - w59_coords$long, + w59_coords$lon, "miles" ) -# The combined distance of multiple points on a track can be computed as well. +# The total distance along a sequence of points can be computed. Consider the +# following sequence of points along Park Ave in the form of a list of points +# where each point is a list containing a `lat` and `lon` tag. park_ave_coords <- list( - list(lat=40.735337983655434, long=-73.98973648773142), # E 15 St / Park Ave - list(lat=40.74772623378332, long=-73.98066078090876), # E 35 St / Park Ave - list(lat=40.76026319186414, long=-73.97149360922498), # E 55 St / Park Ave - list(lat=40.77301604875587, long=-73.96217737679450) # E 75 St / Park Ave + list(lat=40.735337983655434, lon=-73.98973648773142), # E 15 St + list(lat=40.74772623378332, lon=-73.98066078090876), # E 35 St + list(lat=40.76026319186414, lon=-73.97149360922498), # E 55 St + list(lat=40.77301604875587, lon=-73.96217737679450) # E 75 St ) -sum( - sapply( - seq_along(park_ave_coords)[-1], - \(i) get_haversine_distance( - park_ave_coords[[i]]$lat, - park_ave_coords[[i]]$long, - park_ave_coords[[i - 1]]$lat, - park_ave_coords[[i - 1]]$long, - "miles" +# We can create a function to compute the total distance as follows: +compute_total_distance <- function(coords) { + sum( + sapply( + seq_along(coords)[-1], + \(i) get_haversine_distance( + coords[[i]]$lat, + coords[[i]]$lon, + coords[[i - 1]]$lat, + coords[[i - 1]]$lon, + "miles" + ) ) ) -) +} + +# Then applying the function to our sequence results in a total distance. +compute_total_distance(park_ave_coords) } \references{ \url{https://en.wikipedia.org/wiki/Haversine_formula} diff --git a/R/package/man/read_gpx.Rd b/R/package/man/read_gpx.Rd index fb96965..d018237 100644 --- a/R/package/man/read_gpx.Rd +++ b/R/package/man/read_gpx.Rd @@ -43,6 +43,6 @@ gpx_export_files <- list.files( ) # Read in all files and combine them into a single data frame -rides <- do.call(rbind, lapply(activity_files, read_gpx)) +rides <- do.call(rbind, lapply(gpx_export_files, read_gpx)) } } diff --git a/R/package/src/RcppExports.cpp b/R/package/src/RcppExports.cpp index 3d1d346..e40509a 100644 --- a/R/package/src/RcppExports.cpp +++ b/R/package/src/RcppExports.cpp @@ -116,17 +116,17 @@ RcppExport SEXP _eddington_E_next(SEXP ridesSEXP) { return rcpp_result_gen; } // get_haversine_distance_ -double get_haversine_distance_(double lat_1, double long_1, double lat_2, double long_2, double r); -RcppExport SEXP _eddington_get_haversine_distance_(SEXP lat_1SEXP, SEXP long_1SEXP, SEXP lat_2SEXP, SEXP long_2SEXP, SEXP rSEXP) { +double get_haversine_distance_(double lat_1, double lon_1, double lat_2, double lon_2, double r); +RcppExport SEXP _eddington_get_haversine_distance_(SEXP lat_1SEXP, SEXP lon_1SEXP, SEXP lat_2SEXP, SEXP lon_2SEXP, SEXP rSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< double >::type lat_1(lat_1SEXP); - Rcpp::traits::input_parameter< double >::type long_1(long_1SEXP); + Rcpp::traits::input_parameter< double >::type lon_1(lon_1SEXP); Rcpp::traits::input_parameter< double >::type lat_2(lat_2SEXP); - Rcpp::traits::input_parameter< double >::type long_2(long_2SEXP); + Rcpp::traits::input_parameter< double >::type lon_2(lon_2SEXP); Rcpp::traits::input_parameter< double >::type r(rSEXP); - rcpp_result_gen = Rcpp::wrap(get_haversine_distance_(lat_1, long_1, lat_2, long_2, r)); + rcpp_result_gen = Rcpp::wrap(get_haversine_distance_(lat_1, lon_1, lat_2, lon_2, r)); return rcpp_result_gen; END_RCPP } diff --git a/R/package/src/haversine.cpp b/R/package/src/haversine.cpp index 3c2488d..4a67071 100644 --- a/R/package/src/haversine.cpp +++ b/R/package/src/haversine.cpp @@ -11,13 +11,13 @@ static inline double deg2rad(double deg) { // [[Rcpp::export]] double get_haversine_distance_(double lat_1, - double long_1, + double lon_1, double lat_2, - double long_2, + double lon_2, double r) { const double dlat = deg2rad(lat_2 - lat_1); - const double dlong = deg2rad(long_2 - long_1); - const double h = hav(dlat) + cos(deg2rad(lat_1)) * cos(deg2rad(lat_2)) * hav(dlong); + const double dlon = deg2rad(lon_2 - lon_1); + const double h = hav(dlat) + cos(deg2rad(lat_1)) * cos(deg2rad(lat_2)) * hav(dlon); return 2 * r * asin(sqrt(std::clamp(h, 0.0, 1.0))); } diff --git a/R/package/tests/testthat/test-gpx.r b/R/package/tests/testthat/test-gpx.r index 2dd2581..956b1cf 100644 --- a/R/package/tests/testthat/test-gpx.r +++ b/R/package/tests/testthat/test-gpx.r @@ -2,18 +2,18 @@ # In NYC, 20 blocks == 1 mile and the grid is diagonal. That makes it the # perfect location for testing the haversine distance formula. -w59_coords <- list(lat=40.76684156255418, long=-73.97908243833855) # W 59th St / 7th Ave -w39_coords <- list(lat=40.75406905512651, long=-73.98830604245481) # W 39th St / 7th Ave +w59_coords <- list(lat=40.76684156255418, lon=-73.97908243833855) # W 59th St / 7th Ave +w39_coords <- list(lat=40.75406905512651, lon=-73.98830604245481) # W 39th St / 7th Ave ave_7_distance <- get_haversine_distance( - w39_coords$lat, w39_coords$long, w59_coords$lat, w59_coords$long, "miles" + w39_coords$lat, w39_coords$lon, w59_coords$lat, w59_coords$lon, "miles" ) park_ave_coords <- list( - list(lat=40.735337983655434, long=-73.98973648773142), # E 15 St / Park Ave - list(lat=40.74772623378332, long=-73.98066078090876), # E 35 St / Park Ave - list(lat=40.76026319186414, long=-73.97149360922498), # E 55 St / Park Ave - list(lat=40.77301604875587, long=-73.96217737679450) # E 75 St / Park Ave + list(lat=40.735337983655434, lon=-73.98973648773142), # E 15 St + list(lat=40.74772623378332, lon=-73.98066078090876), # E 35 St + list(lat=40.76026319186414, lon=-73.97149360922498), # E 55 St + list(lat=40.77301604875587, lon=-73.96217737679450) # E 75 St ) park_ave_distance <- sum( @@ -21,9 +21,9 @@ park_ave_distance <- sum( seq_along(park_ave_coords)[-1], \(i) get_haversine_distance( park_ave_coords[[i]]$lat, - park_ave_coords[[i]]$long, + park_ave_coords[[i]]$lon, park_ave_coords[[i - 1]]$lat, - park_ave_coords[[i - 1]]$long, + park_ave_coords[[i - 1]]$lon, "miles" ) ) @@ -34,18 +34,18 @@ context("Haversine distance formula") test_that("one mile is one mile", { d <- get_haversine_distance( w39_coords$lat, - w39_coords$long, + w39_coords$lon, w59_coords$lat, - w59_coords$long, + w59_coords$lon, "miles" ) expect_equal(d, 1., tolerance = 0.01) d <- get_haversine_distance( w39_coords$lat, - w39_coords$long, + w39_coords$lon, w59_coords$lat, - w59_coords$long, + w59_coords$lon, "kilometers" ) expect_equal(d, 1.62, tolerance = 0.01)