flightconflicts

Tools to analyze conflicts between aircraft.
git clone https://git.eamoncaddigan.net/flightconflicts.git
Log | Files | Refs | README | LICENSE

commit 7db9165f9f86a4b184ecf95788e1f340aab157d5
parent 207bc493c6e269dad55a1dd108c290d0bb96c0a1
Author: eamoncaddigan <eamon.caddigan@gmail.com>
Date:   Fri, 16 Sep 2016 15:50:28 -0400

Looks good for a new, flightpathr::createTrajectory() world

Diffstat:
MNAMESPACE | 3---
MR/checkTrajectories.R | 4++--
DR/createTrajectory.R | 90-------------------------------------------------------------------------------
MR/identifyViolations.R | 3++-
DR/interpolateTrajectory.R | 31-------------------------------
MR/trajectoryToXYZ.R | 2+-
Dman/createTrajectory.Rd | 43-------------------------------------------
Dman/interpolateTrajectory.Rd | 26--------------------------
Dman/is.flighttrajectory.Rd | 12------------
Mtests/testthat/test_calculateSLoWC.R | 1+
Mtests/testthat/test_calculateTCPA.R | 1+
Dtests/testthat/test_interpolateTrajectory.R | 34----------------------------------
12 files changed, 7 insertions(+), 243 deletions(-)

diff --git a/NAMESPACE b/NAMESPACE @@ -2,9 +2,6 @@ export(calculateSLoWC) export(calculateTCPA) -export(createTrajectory) export(identifyLoWC) export(identifyNMAC) -export(interpolateTrajectory) export(is.flattrajectory) -export(is.flighttrajectory) diff --git a/R/checkTrajectories.R b/R/checkTrajectories.R @@ -10,8 +10,8 @@ #' of samples and origin. checkTrajectories <- function(trajectory1, trajectory2) { # Two flight trajectories - if (is.flighttrajectory(trajectory1)) { - if (!is.flighttrajectory(trajectory2)) { + if (flightpathr::is.flighttrajectory(trajectory1)) { + if (!flightpathr::is.flighttrajectory(trajectory2)) { stop("'trajectory1' is a flighttrajectory; 'trajectory2' must match this type") } if (!isTRUE(all.equal(trajectory1$timestamp, trajectory2$timestamp))) { diff --git a/R/createTrajectory.R b/R/createTrajectory.R @@ -1,90 +0,0 @@ -#' Create a flighttrajectory object from the flight info. -#' -#' @param longitude Required; numeric vector giving aircraft longitude in -#' degrees. -#' @param latitude Required; numeric vector giving aircraft latitude in degrees. -#' @param altitude Optional; numeric vector giving aircraft altitude (AGL) in -#' feet. If missing, it will be set to 0. -#' @param timestamp Optional; numeric vector giving the time of each observation -#' in seconds. If missing, the observation period is assumed to be 1 s. -#' @param bearing Optional; numeric vector giving the current bearing in -#' degrees. If missing, it is estimated using pairs of successive lon/lat -#' observations. -#' @param groundspeed Optional; numeric vector giving the current ground speed -#' of the aircraft in knots. If missing, it is estimated using pairs of -#' successive lon/lat observations. -#' @return A flighttrajectory object encapsulating these parameters (with -#' default values substituded as necessary). -#' -#' @details \code{longitude} and \code{latitude} must be the same length. -#' \code{timestamp}, \code{bearing}, and \code{groundspeed}, if present, must -#' also match this length. \code{altitude} must also have a length equal to -#' these parameters or be scalar. -#' -#' @export -createTrajectory <- function(longitude, latitude, altitude = 0, timestamp = NULL, - bearing = NULL, groundspeed = NULL) { - if (!is.numeric(longitude)) stop("\"longitude\" must be a numeric vector") - nCoord <- length(longitude) - - # Helper function to throw an error if the length of a vector is incorrect. - checkLength <- function(x) { - if (!is.numeric(x)) { - stop("\"", deparse(substitute(x)), "\" must be a numeric vector") - } else if (length(x) != nCoord) { - stop("Vector \"", deparse(substitute(x)), "\" has length = ", length(x), - ", expected length = ", nCoord) - } - return(TRUE) - } - - checkLength(latitude) - coords <- cbind(longitude, latitude) - - if (length(altitude) == 1) { - altitude <- rep(altitude, nCoord) - } else { - checkLength(altitude) - } - - if (is.null(timestamp)) { - timestamp <- seq(1, nCoord) - } else { - checkLength(timestamp) - } - - # Use flightpathr to calculate bearing between successive points if not - # specified. - if (is.null(bearing)) { - bearing <- flightpathr::coordsToBearing(cbind(coords, altitude)) - bearing[nCoord] <- bearing[nCoord-1] - } else { - checkLength(bearing) - } - - # Use geosphere to find the distance between points and use the timestamps to - # calculate groundspeed if not specified. - if (is.null(groundspeed)) { - distNM <- geosphere::distCosine(coords[1:(nCoord-1), ], - coords[2:nCoord, ], - r = 3444) - groundspeed <- distNM / diff(timestamp) * 3600 - groundspeed <- c(groundspeed, groundspeed[nCoord-1]) - } else{ - checkLength(groundspeed) - } - - flighttrajectory <- list(longitude = longitude, - latitude = latitude, - altitude = altitude, - timestamp = timestamp, - bearing = bearing, - groundspeed = groundspeed) - class(flighttrajectory) <- "flighttrajectory" - - return(flighttrajectory) -} - -#' Check if an object is a flighttrajectory -#' @export -is.flighttrajectory <- function(x) inherits(x, "flighttrajectory") diff --git a/R/identifyViolations.R b/R/identifyViolations.R @@ -13,7 +13,8 @@ #' #' @export identifyNMAC <- function(trajectory1, trajectory2) { - if (!is.flighttrajectory(trajectory1) || !is.flighttrajectory(trajectory2)) { + if (!flightpathr::is.flighttrajectory(trajectory1) || + !flightpathr::is.flighttrajectory(trajectory2)) { stop("Both arguments must be instances of flighttrajectory") } if (!isTRUE(all.equal(trajectory1$timestamp, trajectory2$timestamp))) { diff --git a/R/interpolateTrajectory.R b/R/interpolateTrajectory.R @@ -1,31 +0,0 @@ -#' Interpolate a trajectory (in time) -#' -#' @param trajectory A \code{flighttrajectory} object. -#' @param timestamp The new timestamp along which the data should be -#' interpolated. -#' @return A new \code{flighttrajectory} with the given \code{timestamp} -#' -#' @details This just performs linear interpolation for all of the values in the -#' trajectory. A better approach would make use of the bearing and velocity -#' information to smoothly interpolate the coordinates. -#' -#' @export -interpolateTrajectory <- function(trajectory, timestamp) { - # We'll interpolate all of the features (except the timestamp, which is - # specified). - trajectoryFeatures <- names(trajectory) - trajectoryFeatures <- trajectoryFeatures[trajectoryFeatures != "timestamp"] - - # Create a new trajectory with - newTrajectory <- list() - for (trajectoryFeature in trajectoryFeatures) { - newTrajectory[[trajectoryFeature]] <- approx(x = trajectory$timestamp, - y = trajectory[[trajectoryFeature]], - xout = timestamp, - method = "linear", - rule = 2)$y - } - newTrajectory[["timestamp"]] <- timestamp - - return(do.call(createTrajectory, newTrajectory)) -} diff --git a/R/trajectoryToXYZ.R b/R/trajectoryToXYZ.R @@ -5,7 +5,7 @@ #' conversion. #' @return A flattrajectory object. trajectoryToXYZ <- function(trajectory, origin) { - if (!is.flighttrajectory(trajectory)) { + if (!flightpathr::is.flighttrajectory(trajectory)) { stop("'trajectory' must be an instance of flighttrajectory") } if (!is.numeric(origin) || length(origin) != 2) { diff --git a/man/createTrajectory.Rd b/man/createTrajectory.Rd @@ -1,43 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/createTrajectory.R -\name{createTrajectory} -\alias{createTrajectory} -\title{Create a flighttrajectory object from the flight info.} -\usage{ -createTrajectory(longitude, latitude, altitude = 0, timestamp = NULL, - bearing = NULL, groundspeed = NULL) -} -\arguments{ -\item{longitude}{Required; numeric vector giving aircraft longitude in -degrees.} - -\item{latitude}{Required; numeric vector giving aircraft latitude in degrees.} - -\item{altitude}{Optional; numeric vector giving aircraft altitude (AGL) in -feet. If missing, it will be set to 0.} - -\item{timestamp}{Optional; numeric vector giving the time of each observation -in seconds. If missing, the observation period is assumed to be 1 s.} - -\item{bearing}{Optional; numeric vector giving the current bearing in -degrees. If missing, it is estimated using pairs of successive lon/lat -observations.} - -\item{groundspeed}{Optional; numeric vector giving the current ground speed -of the aircraft in knots. If missing, it is estimated using pairs of -successive lon/lat observations.} -} -\value{ -A flighttrajectory object encapsulating these parameters (with - default values substituded as necessary). -} -\description{ -Create a flighttrajectory object from the flight info. -} -\details{ -\code{longitude} and \code{latitude} must be the same length. - \code{timestamp}, \code{bearing}, and \code{groundspeed}, if present, must - also match this length. \code{altitude} must also have a length equal to - these parameters or be scalar. -} - diff --git a/man/interpolateTrajectory.Rd b/man/interpolateTrajectory.Rd @@ -1,26 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/interpolateTrajectory.R -\name{interpolateTrajectory} -\alias{interpolateTrajectory} -\title{Interpolate a trajectory (in time)} -\usage{ -interpolateTrajectory(trajectory, timestamp) -} -\arguments{ -\item{trajectory}{A \code{flighttrajectory} object.} - -\item{timestamp}{The new timestamp along which the data should be -interpolated.} -} -\value{ -A new \code{flighttrajectory} with the given \code{timestamp} -} -\description{ -Interpolate a trajectory (in time) -} -\details{ -This just performs linear interpolation for all of the values in the - trajectory. A better approach would make use of the bearing and velocity - information to smoothly interpolate the coordinates. -} - diff --git a/man/is.flighttrajectory.Rd b/man/is.flighttrajectory.Rd @@ -1,12 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/createTrajectory.R -\name{is.flighttrajectory} -\alias{is.flighttrajectory} -\title{Check if an object is a flighttrajectory} -\usage{ -is.flighttrajectory(x) -} -\description{ -Check if an object is a flighttrajectory -} - diff --git a/tests/testthat/test_calculateSLoWC.R b/tests/testthat/test_calculateSLoWC.R @@ -2,6 +2,7 @@ library(flightconflicts) context("calculateSLoWC") library(geosphere) +library(flightpathr) # I'll attempt to replicate the values in Appendix A of SC-228. diff --git a/tests/testthat/test_calculateTCPA.R b/tests/testthat/test_calculateTCPA.R @@ -2,6 +2,7 @@ library(flightconflicts) context("calculateTCPA") library(geosphere) +library(flightpathr) kacy <- c(-74.5771667, 39.4575833) kphl <- c(-75.2408658, 39.8722494) diff --git a/tests/testthat/test_interpolateTrajectory.R b/tests/testthat/test_interpolateTrajectory.R @@ -1,34 +0,0 @@ -library(flightconflicts) -context("interpolateTrajectory") - -library(geosphere) - -kacy <- c(-74.5771667, 39.4575833) -k17n <- c(-75.0330031, 39.7054758) - -# Two identical trajectories with different sampling rates -coords1 <- gcIntermediate(kacy, k17n, n = 61) -trajectory1 <-createTrajectory(coords1[, 1], coords1[, 2], altitude = 3500, - timestamp = seq(0, 800, length.out = 61)) -coords2 <- gcIntermediate(kacy, k17n, n = 229) -trajectory2 <-createTrajectory(coords2[, 1], coords2[, 2], altitude = 3500, - timestamp = seq(0, 800, length.out = 229)) - -test_that("Interpolated trajectory is close to correct", { - trajectoryInterpolated <- interpolateTrajectory(trajectory1, - trajectory2$timestamp) - - for (tf in names(trajectoryInterpolated)) { - expect_equal(trajectoryInterpolated[[tf]], trajectory2[[tf]], tolerance = 1) - } -}) - -test_that("Correctly handling times outside original range", { - trajectoryInterpolated <- interpolateTrajectory(trajectory1, - c(-100, 0, 800, 900)) - - for (tf in names(trajectoryInterpolated)[names(trajectoryInterpolated) != "timestamp"]) { - expect_equal(trajectoryInterpolated[[tf]][1], trajectoryInterpolated[[tf]][2]) - expect_equal(trajectoryInterpolated[[tf]][3], trajectoryInterpolated[[tf]][4]) - } -})