test_that("before and after give sensible outputs", { x <- numeric() expect_equal(length(before(x)), 0) expect_equal(length(after(x)), 0) x <- 1:5 expect_equal(before(x), c(1, 1:5)) expect_equal(after(x), c(1:5, 5)) }) test_that("angle_from_xy gives correct results", { # Equilateral triangle t <- seq(pi, -pi, length.out = 4) x <- cos(t) y <- sin(t) # Correct angles (*not* -30, 90, 30 as one might expect) ang <- angle_from_xy(x, y, degrees = TRUE) expect_equal(ang, c(30, -90, 150)) # Reverse path should gave same angles as forward path, but negative ang_test <- angle_from_xy(rev(x), rev(y), degrees = TRUE) expect_equal(ang_test, -ang) # Radian and degree mode give same angles ang_test <- angle_from_xy(x, y, degrees = FALSE) expect_equal(ang_test, ang / 180 * pi) # Normal should be 90 degrees offset ang_test <- angle_from_xy(x, y, norm = TRUE, degrees = TRUE) expect_equal(ang_test, ang + 90) # Should be able to handle length-2 vectors ang_test <- angle_from_xy(x[1:2], y[1:2], degrees = TRUE) expect_equal(ang_test, 30) x <- unit(c(0, 1), "in") y <- unit(c(0, 1), "in") expect_equal(angle_from_xy(x, y, degrees = TRUE), 45) }) test_that("arclength_from_xy gives correct results", { # Vector mode lens <- runif(50) angles <- runif(50, max = 2 * pi) x <- cumsum(lens * cos(angles)) y <- cumsum(lens * sin(angles)) arclen <- arclength_from_xy(x, y) expect_equal(arclen[50], sum(lens[2:50])) # Matrix mode x <- cbind(x[1:25], x[26:50]) y <- cbind(y[1:25], y[26:50]) arclen <- arclength_from_xy(x, y) expect_equal(arclen[25, ], c(sum(lens[2:25]), sum(lens[27:50]))) x <- unit(c(0, 3), "npc") y <- unit(c(0, 4), "npc") expect_equal(arclength_from_xy(x, y), c(0, 5)) expect_equal(arclength_from_xy(0, 0), 0) expect_equal(arclength_from_xy(0, NA), as.numeric(NA)) expect_equal(arclength_from_xy(NA, 0), as.numeric(NA)) }) test_that("get_offset offsets correctly", { x <- c(1:5) y <- c(1, 2, 3, 2, 1) offset <- get_offset(x, y, d = 1:2 / sqrt(2)) expect_equal( offset$x, cbind(c(0.5, 1.5, 3, 4.5, 5.5), c(0, 1, 3, 5, 6)) ) expect_equal( offset$y, cbind(c(1.5, 2.5, 4, 2.5, 1.5), c(2, 3, 5, 3, 2)) ) expect_equal( offset$arc_length, cbind(c(0, 2, 5, 8, 10), c(0, 2, 6, 10, 12)) / sqrt(2) ) }) test_that("We can measure curvature accurately", { # x and y describe a circle with radius 1: t <- seq(0, 360, length.out = 1000) * pi / 180 x <- cos(t) y <- sin(t) curv_1 <- get_curvature(x, y) # the curvature should be the reciprocal of the radius radius_1 <- 1 / curv_1 expect_true( all(abs(radius_1 - 1) < 0.001) ) # Doubling the radius of the circle should half the curvature curv_2 <- get_curvature(2 * x, 2 * y) expect_true( all(abs((curv_1 / curv_2) - 2) < 0.001) ) }) test_that("We can roll our own means", { val <- c(4.25, 5.75, 5.75, 6, 5.5, 5.5, 5, 6, 5, 3.5, 4) expect_equal(val, safe_rollmean(c(3, 8, 9, 3, 4, 6, 9, 1, 8, 2, 3), k = 4)) expect_equal(val, safe_rollmean(val, k = 1)) }) test_that("We can find the flattest point of a curve", { x <- 1:100 y <- sin(seq(0, 2 * pi, len = 100)) expect_equal(which.min_curvature(x, y), 1) }) test_that("We can smooth a noisy path", { x <- seq(0, 2 * pi, len = 100) y <- sin(x) + 0.3 * sin(x * 20) id <- rep(1, 100) length <- arclength_from_xy(x, y) df <- data.frame(x = x, y = y, length = length, id = id) df$x <- grid::unit(x, "npc") df$y <- grid::unit(y, "npc") a <- smooth_noisy(df, 1) x1 <- as.numeric(a$x) y1 <- as.numeric(a$y) expect_true(has_corners(x, y)) expect_false(has_corners(x1, y1)) }) test_that("We can get a 1-d quadratic Bezier", { expected <- (0:10 - 5)^2 actual <- quad_bezier(25, -25, 25, seq(0, 1, 0.1)) expect_equal(actual, expected) }) test_that("Corners are smoothed appropriately", { expected <- structure(list(x = c(0, 1, 4, 9, 16), y = c(0, 7, 12, 15, 16), line_x = c(0, 0, 0, 8, 16), line_y = c(0, 8, 16, 16, 16), line_length = c(0, 8, 16, 24, 32)), class = "data.frame", row.names = c(NA, -5L)) actual <- corner_smoother(c(0, 0), c(0, 1), c(1, 1), p = 5) expect_equal(actual[-3], expected / 16) p1 <- p2 <- p3 <- c(0, 1) nms <- c("x", "y", "length", "line_x", "line_y", "line_length") expect <- matrix(rep(c(0, 1, 0, 0, 1, 0), each = 20), nrow = 20) expect <- setNames(as.data.frame(expect), nms) expect_equal(corner_smoother(p1, p2, p3), expect) df <- data.frame(x = rep(0, 11), y = 0:10, length = 0:10, line_x = 0, line_y = 0:10, line_length = 0:10) expect_equal(corner_smoother(c(0, 0), c(0, 10), c(0, 10), 11), df) expect_equal(corner_smoother(c(0, 0), c(0, 0), c(0, 10), 11), df) }) test_that("We can make a data frame of points between two given points", { actual <- linear_smooth(p1 = c(0, 0), p2 = c(0, 10), n = 11) df <- data.frame(x = rep(0, 11), y = 0:10, length = 0:10, line_x = 0, line_y = 0:10, line_length = 0:10) expect_equal(actual, df) }) test_that("We can get Bezier control points from segments and paths", { x <- 0 y <- 0 ang <- pi / 4 len <- sqrt(2) radius <- 0.1 d <- sqrt(0.02) / 2 expect <- matrix(rep(c(0, d, 0.5, 1 - d), 2), ncol = 2) expect_equal(segment_control_points(x, y, len, ang, radius), expect) expect_equal(segment_control_points(x, y, len, ang, 1), matrix(c(0, 1, 0, 1), 2) / 2) actual <- find_control_points(data.frame(x = 0:2, y = c(0, 1, 0)), 0.1) expect <- c(c(0, 0, d, 0.5, 1 - d, 1, 1 + d, 1.5, 2 - d, 2, 2), c(0, 0, d, 0.5, 1 - d, 1, 1 - d, 0.5, d, 0, 0)) expect <- matrix(expect, ncol = 2) expect_equal(actual, expect) sc <- smooth_corners(data.frame(x = 0:2, y = c(0, 1, 0)), n = 3, radius = 0.1) vec <- c(0, d / 2, d, d, 0.5, 1 - d, 1 - d) x <- c(vec, 1, 2 - rev(vec)) y <- c(vec, 1 - d / 2, rev(vec)) len <- cumsum(c(0, sqrt(diff(x)^2 + diff(y)^2))) line_len <- c(0, 0.05, 0.1, 0.1, sqrt(2) / 2, sqrt(2) - 0.1, sqrt(2) - 0.1, sqrt(2), sqrt(2) + 0.1, sqrt(2) + 0.1, sqrt(2) * 3 / 2, 2 * sqrt(2) - 0.1, 2 * sqrt(2) - 0.1, 2*sqrt(2) - 0.05, 2 * sqrt(2)) df <- data.frame(x = x, y = y, length = len, line_x = x, line_y = y, line_length = line_len, segment = rep(1:5, each = 3)) df$line_y[8] <- 1 expect_equal(sc, df) }) test_that("We can apply both smoothing types", { x <- unit((0:2) / 2, "npc") y <- unit(c(0, 1, 0), "npc") label <- "X" id <- c(1, 1, 1) png("Rplot_test.png", width = 7, height = 7, units = "in", res = 100) grob <- textpathGrob(label, x, y, id, text_smoothing = 50) grob <- makeContent(grob) x <- convertUnit(grob$children[[2]]$x, "npc", valueOnly = TRUE) y <- convertUnit(grob$children[[2]]$y, "npc", valueOnly = TRUE) dev.off() unlink("Rplot_test.png") expect_lt(abs(x - 0.5), 0.001) expect_lt(abs(y - 0.9852688), 0.001) })