flightpathr

Tools to analyze aircraft and flight path data.
git clone https://git.eamoncaddigan.net/flightpathr.git
Log | Files | Refs | README | LICENSE

commit 88a44af77331ffef32372e35ec8215485f1ce95a
parent 653e59268223de4704bd6ae2d5c59f291b6dcf50
Author: eamoncaddigan <eamon.caddigan@gmail.com>
Date:   Wed, 21 Sep 2016 15:40:57 -0400

distanceFromPath() based on flighttrajectory and flightpath objects.

Diffstat:
MR/distanceFromPath.R | 6+++---
Mman/distanceFromPath.Rd | 6+++---
Mtests/testthat/test_distanceFromPath.R | 102++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
3 files changed, 65 insertions(+), 49 deletions(-)

diff --git a/R/distanceFromPath.R b/R/distanceFromPath.R @@ -1,9 +1,9 @@ #' Calculate the distance of a flight trajectory from a flight path. #' -#' @param trajectory A matrix or SpatialPoints object indicating the trajectory +#' @param trajectory A \code{flighttrajectory} object indicating the trajectory #' of an aircraft. -#' @param path A matrix or SpatialPoints object indicating the ordered waypoints -#' a pre-defined flight path. +#' @param path A \code{flightpath} object indicating the ordered waypoints a +#' pre-defined flight path. #' @return A data.frame containing two columns representing the distance between #' the aircraft and its planned flight path (in feet): \code{horizontal} #' indicates the horizontal distance and \code{vertical} indicates the diff --git a/man/distanceFromPath.Rd b/man/distanceFromPath.Rd @@ -7,11 +7,11 @@ distanceFromPath(trajectory, path) } \arguments{ -\item{trajectory}{A matrix or SpatialPoints object indicating the trajectory +\item{trajectory}{A \code{flighttrajectory} object indicating the trajectory of an aircraft.} -\item{path}{A matrix or SpatialPoints object indicating the ordered waypoints -a pre-defined flight path.} +\item{path}{A \code{flightpath} object indicating the ordered waypoints a +pre-defined flight path.} } \value{ A data.frame containing two columns representing the distance between diff --git a/tests/testthat/test_distanceFromPath.R b/tests/testthat/test_distanceFromPath.R @@ -1,3 +1,5 @@ +# TODO: Handle NA altitudes in flightpaths. + library(flightpathr) context("distanceFromPath") @@ -5,77 +7,91 @@ distancePrecision <- 10 numPoints <- 5 fakeTrajectory <- function(waypoints, n = numPoints) { - trajectoryList <- vector("list", 2*nrow(waypoints)-1) - trajectoryList[[1]] <- waypoints[1, ] + coordList <- vector("list", 2*nrow(waypoints)-1) + coordList[[1]] <- waypoints[1, ] for (i in seq(2, nrow(waypoints))) { - trajectoryList[[(i-1)*2]] <- geosphere::gcIntermediate(waypoints[i-1, ], + coordList[[(i-1)*2]] <- geosphere::gcIntermediate(waypoints[i-1, ], waypoints[i, ], n) - trajectoryList[[(i-1)*2+1]] <- waypoints[i, ] + coordList[[(i-1)*2+1]] <- waypoints[i, ] } - return(do.call(rbind, trajectoryList)) + coordMat <- do.call(rbind, coordList) + return(createTrajectory(longitude = coordMat[, "lon"], + latitude = coordMat[, "lat"], + altitude = 0)) } # Flying from 17N to KACY with a stop over N81. Flying VFR at 3500 msl -path <- matrix(c(-75.0268, 39.7065, +pathMat <- matrix(c(-75.0268, 39.7065, -74.7577, 39.6675, -74.5722, 39.4513), nrow = 3, byrow = TRUE, dimnames = list(c("17N", "N81", "KACY"), c("lon", "lat"))) -trajectory <- fakeTrajectory(path) +path <- createPath(longitude = pathMat[, "lon"], latitude = pathMat[, "lat"], + altitude = 0) +trajectory <- fakeTrajectory(pathMat) +trajectoryLength <- length(trajectory$longitude) test_that("non-deviating paths have small distances for all input types", { - expect_true(all(distanceFromPath(trajectory, path) < distancePrecision)) - expect_true(all(distanceFromPath(cbind(trajectory, 3500), cbind(path, 3500)) < distancePrecision)) - expect_true(all(distanceFromPath(sp::SpatialPoints(trajectory), sp::SpatialPoints(path)) < distancePrecision)) - expect_true(all(distanceFromPath(as.data.frame(trajectory), as.data.frame(path)) < distancePrecision)) + expect_equal(distanceFromPath(trajectory, path)$horizontal, + rep(0, trajectoryLength), + tolerance = 1) + # Leaving these here but commented-out. I'd like to be able to accept multiple + # input types again later, but it's a low priority. + + # expect_true(all(distanceFromPath(cbind(trajectory, 3500), cbind(path, 3500)) < distancePrecision)) + # expect_true(all(distanceFromPath(sp::SpatialPoints(trajectory), sp::SpatialPoints(path)) < distancePrecision)) + # expect_true(all(distanceFromPath(as.data.frame(trajectory), as.data.frame(path)) < distancePrecision)) }) test_that("small deviations look OK", { - flownPath <- rbind(path[1:2, ], + flownPathMat <- rbind(pathMat[1:2, ], KORDE = c(-74.0948, 39.0976), - path[3, , drop = FALSE]) - flownTrajectory <- fakeTrajectory(flownPath) + pathMat[3, , drop = FALSE]) + flownTrajectory <- fakeTrajectory(flownPathMat) + flownPath <- createPath(flownPathMat[, 1], flownPathMat[, 2], 0) trajectoryDistance <- distanceFromPath(flownTrajectory, path)$horizontal farthestPoint <- which.max(abs(trajectoryDistance)) expect_equal(farthestPoint, numPoints*2+3) - - expect_lt(abs(maxDistanceFromPath(flownTrajectory, path)["horizontal"] - 42015.6), - distancePrecision) - expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath)["horizontal"] - 0), - distancePrecision) -}) - -test_that("simple altitude deviation is handled", { - flownPath1 <- cbind(path, alt = 3500) - flownPath2 <- cbind(path, alt = c(3500, 4500, 3500)) - flownPath3 <- cbind(path, alt = c(3500, 5500, 3500)) - flownPath4 <- cbind(path, alt = c(3500, 5500, 5500)) - flownTrajectory <- cbind(fakeTrajectory(path), - alt = c(seq(3500, 5500, length.out = numPoints+2), - seq(5500, 3500, - length.out = nrow(trajectory)-(numPoints+2)))) - - expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath1)["vertical"] - 2000), - distancePrecision) - expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath2)["vertical"] - 1000), - distancePrecision) - expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath3)["vertical"] - 0000), - distancePrecision) - expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath4)["vertical"] - -2000), - distancePrecision) + expect_equal(maxDistanceFromPath(flownTrajectory, path)["horizontal"], + c(horizontal = 42015.6), + tolerance = 1) + expect_equal(maxDistanceFromPath(flownTrajectory, flownPath)["horizontal"], + c(horizontal = 0), + tolerance = 1) }) +# test_that("simple altitude deviation is handled", { +# flownPath1 <- cbind(path, alt = 3500) +# flownPath2 <- cbind(path, alt = c(3500, 4500, 3500)) +# flownPath3 <- cbind(path, alt = c(3500, 5500, 3500)) +# flownPath4 <- cbind(path, alt = c(3500, 5500, 5500)) +# flownTrajectory <- cbind(fakeTrajectory(path), +# alt = c(seq(3500, 5500, length.out = numPoints+2), +# seq(5500, 3500, +# length.out = nrow(trajectory)-(numPoints+2)))) +# +# expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath1)["vertical"] - 2000), +# distancePrecision) +# expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath2)["vertical"] - 1000), +# distancePrecision) +# expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath3)["vertical"] - 0000), +# distancePrecision) +# expect_lt(abs(maxDistanceFromPath(flownTrajectory, flownPath4)["vertical"] - -2000), +# distancePrecision) +# }) +# test_that("reproducing geosphere vignette example", { LA <- c(-118.40, 33.95) NY <- c(-73.78, 40.63) MS <- c(-93.26, 44.98) - plannedPath <- rbind(LA, NY) flownTrajectory <- fakeTrajectory(rbind(LA, MS, NY), n = 1000) + plannedPathMat <- rbind(LA, NY) + plannedPath <- createPath(plannedPathMat[, 1], plannedPathMat[, 2], 0) feetToMeters <- 0.3048 - expect_lt(abs(maxDistanceFromPath(flownTrajectory, plannedPath)["horizontal"]*feetToMeters - - 547448.8), - 1) + expect_equal(maxDistanceFromPath(flownTrajectory, plannedPath)["horizontal"]*feetToMeters, + c("horizontal" = 547448.8), + tolerance = 1) })