-
Notifications
You must be signed in to change notification settings - Fork 1
/
max_ad.R
91 lines (85 loc) · 2.91 KB
/
max_ad.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#' @title (signed) Maximum Absolute Deviation
#'
#' @description Computes the (signed) Maximum Absolute Deviation (MAD) of a
#' path, defined by vectors of x and y coordinates, as compared to an
#' ideal line passing through the start and end points.
#'
#' @inheritParams auc
#'
#' @returns (signed) MAD as single number (-Inf to +Inf).
#'
#' @details The ideal line is a line, not a line segment, i.e., it has
#' infinite length. The supplied vectors are assumed to be ordered by time.
#' Counterclockwise deviations from the ideal line are considered
#' positive, clockwise deviations as negative for the computation of the MAD.
#' Thus, negative MADs are possible. If more than one value is
#' considered maximal, the first maximal value is returned.
#'
#' @references Wirth, R., Foerster, A., Kunde, W., & Pfister, R. (2020).
#' Design choices: Empirical recommendations for designing two-dimensional
#' finger tracking experiments. Behavior Research Methods, 52, 2394 - 2416.
#' \doi{10.3758/s13428-020-01409-0}
#'
#'
#' @examples
#' x_vals <- c(0, 0, 0, 1, 2)
#' y_vals <- c(0, 1, 2, 2, 2)
#' plot(x_vals, y_vals, type = "l")
#' lines(c(0, 2), c(0, 2), lty = "dashed", lwd = 2) # ideal
#' max_ad(x_vals, y_vals) # counterclockwise deviation: positive
#'
#' x_vals <- c(0, 1, 2, 2, 2)
#' y_vals <- c(0, 0, 0, 1, 2)
#' plot(x_vals, y_vals, type = "l")
#' lines(c(0, 2), c(0, 2), lty = "dashed", lwd = 2) # ideal
#' max_ad(x_vals, y_vals) # clockwise deviation: negative
#' x_vals <- -x_vals
#' max_ad(x_vals, y_vals) # now it is counterclockwise again
#'
#' x_vals <- c(0, 0, 1, 2, 3, 6, 3)
#' y_vals <- c(0, 2, 2, 2, 2, 1, 0)
#' plot(x_vals, y_vals, type = "l")
#' lines(c(0, 3), c(0, 0), lty = "dashed", lwd = 2) # ideal
#' max_ad(x_vals, y_vals) # the ideal trajectory has infinite length
#'
#' x_vals <- c(0, 1, 2, 3)
#' y_vals <- c(0, 1, -1, 0)
#' plot(x_vals, y_vals, type = "l")
#' lines(x_vals, -y_vals, col = "red")
#' lines(c(0, 3), c(0, 0), lty = "dashed", lwd = 2) # ideal
#' max_ad(x_vals, y_vals)
#' max_ad(x_vals, -y_vals) # the "first" maximal value is returned
#'
#' @export
#'
max_ad <- function(x_vector,
y_vector,
x_start,
y_start,
x_end,
y_end) {
# check for optional parameters
if (missing(x_start)) {
x_start <- x_vector[1]
}
if (missing(y_start)) {
y_start <- y_vector[1]
}
if (missing(x_end)) {
x_end <- x_vector[length(x_vector)]
}
if (missing(y_end)) {
y_end <- y_vector[length(x_vector)]
}
# shift data
x_shift <- x_vector - x_start
y_shift <- y_vector - y_start
# rotate data to ideal trajectory, as defined by start to end points
angle <- atan2((y_end - y_start), (x_end - x_start))
m_sin <- sin(-angle)
m_cos <- cos(-angle)
y_rot <- (x_shift * m_sin) + (y_shift * m_cos)
# find the index of maximum deviation from ideal trajectory
index <- which.max(abs(y_rot))
return(y_rot[index])
}