distanceFromPath.R (3566B)
1 #' Calculate the distance of a flight trajectory from a flight path. 2 #' 3 #' @param trajectory A \code{flighttrajectory} object (or an object that can be 4 #' coerced into one) indicating the trajectory of an aircraft. 5 #' @param path A \code{flightpath} object (or an object that can be coerced into 6 #' one) indicating the ordered waypoints a pre-defined flight path. 7 #' @return A data.frame containing two columns representing the distance between 8 #' the aircraft and its planned flight path (in feet): \code{horizontal} 9 #' indicates the horizontal distance and \code{vertical} indicates the 10 #' vertical distance. 11 #' 12 #' @export 13 distanceFromPath <- function(trajectory, path) { 14 # Check inputs and get 3D coordinates 15 trajectoryCoords <- get3dCoords(as.flighttrajectory(trajectory)) 16 pathCoords <- get3dCoords(as.flightpath(path)) 17 18 numLegs <- nrow(pathCoords)-1 19 20 # Given n points and m legs, store horizontal and vertical distance in an 21 # n x m arrays 22 hDistanceToLeg <- array(NA, dim = c(nrow(trajectoryCoords), numLegs)) 23 vDistanceToLeg <- array(NA, dim = c(nrow(trajectoryCoords), numLegs)) 24 25 # And the squared "slant range" (euclidean distance) in an n x m array 26 slantToLeg <- array(NA, dim = c(nrow(trajectoryCoords), numLegs)) 27 28 for (legIdx in seq_len(numLegs)) { 29 # For each pair of adjascent waypoints, calculate the horizontal distance 30 # from the great circle defined by the pair and all points in the 31 # trajectory. 32 hDistanceToLeg[, legIdx] <- geosphere::dist2gc(pathCoords[legIdx, c(1,2)], 33 pathCoords[legIdx+1, c(1,2)], 34 trajectoryCoords[, c(1,2)], 35 r = 20925646) 36 37 38 if (is.na(pathCoords[legIdx, 3]) || is.na(pathCoords[legIdx+1, 3])) { 39 # When a waypoint has an altidue of NA, we don't care about its altitude. 40 # Therefore, the "vertical deviation" is meaningless. Use 0. 41 vDistanceToLeg[, legIdx] <- 0 42 } else if (pathCoords[legIdx, 3] == pathCoords[legIdx+1, 3]) { 43 # If the waypoints are at the same altitude, just calculate the deviation 44 # from this altitude. Easy. 45 vDistanceToLeg[, legIdx] <- trajectoryCoords[, 3] - pathCoords[legIdx, 3] 46 } else { 47 # When waypoints have different altitudes, a flight has "deviated" when 48 # it's above the higher altitude or below the lower altitude. 49 vDistanceToLeg[, legIdx] <- 0 50 deviationAbove <- trajectoryCoords[, 3] - max(pathCoords[c(legIdx, legIdx+1), 3]) 51 deviationBelow <- trajectoryCoords[, 3] - min(pathCoords[c(legIdx, legIdx+1), 3]) 52 vDistanceToLeg[deviationAbove > 0, legIdx] <- deviationAbove[deviationAbove > 0] 53 vDistanceToLeg[deviationBelow < 0, legIdx] <- deviationBelow[deviationBelow < 0] 54 } 55 56 # Squared euclidean distance 57 slantToLeg[, legIdx] <- hDistanceToLeg[, legIdx]^2 + vDistanceToLeg[, legIdx]^2 58 } 59 60 # Figure out which leg is closer to each point in the trajectory. 61 # Note: I can imagine a tortuous path that would result in the closest path 62 # alternating between legs. This would need to be rewritten to handle that. 63 closestLeg <- apply(slantToLeg, 1, which.min) 64 65 # Return the horizontal and vertical distance to the flight path (distance to 66 # the closest leg) as a data.frame. 67 distanceToPath <- data.frame(horizontal = hDistanceToLeg[cbind(1:nrow(trajectoryCoords), closestLeg)], 68 vertical = vDistanceToLeg[cbind(1:nrow(trajectoryCoords), closestLeg)]) 69 return(distanceToPath) 70 }