tests/testthat/test-nn.R

test_that("geodesic_nn finds correct nearest neighbors", {
  # Simple dataset
  dataset <- cbind(
    lon = c(0, 10, 20, 30),
    lat = c(0, 0, 0, 0)
  )
  
  # Query at origin - nearest should be first point
 result <- geodesic_nn(dataset, c(0, 0), k = 1)
  expect_equal(result$index[1, 1], 1L)
  expect_equal(result$distance[1, 1], 0, tolerance = 1e-6)
  
  # Query at (5, 0) - nearest should be either point 1 or 2
  result <- geodesic_nn(dataset, c(5, 0), k = 2)
  expect_true(all(result$index[, 1] %in% c(1L, 2L)))
})

test_that("geodesic_nn returns correct dimensions", {
  dataset <- cbind(
    lon = c(0, 10, 20, 30, 40),
    lat = c(0, 10, 20, 30, 40)
  )
  
  queries <- cbind(
    lon = c(5, 15, 25),
    lat = c(5, 15, 25)
  )
  
  result <- geodesic_nn(dataset, queries, k = 3)
  
  # Should be k x n_queries
  expect_equal(dim(result$index), c(3, 3))
  expect_equal(dim(result$distance), c(3, 3))
})

test_that("geodesic_nn handles k larger than dataset", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  query <- c(5, 5)
  
  # k=5 but only 2 points - should return 2
  result <- geodesic_nn(dataset, query, k = 5)
  expect_equal(nrow(result$index), 2)
})

test_that("geodesic_nn distances are geodesic", {
  # Two points on equator
  dataset <- cbind(lon = 10, lat = 0)
  query <- c(0, 0)
  
  result <- geodesic_nn(dataset, query, k = 1)
  
  # Compare with geodesic_inverse
  expected <- geodesic_inverse(query, dataset)
  expect_equal(result$distance[1, 1], expected$s12, tolerance = 1)
})

test_that("geodesic_nn_radius finds all points within radius", {
  # Points at known distances from origin
  dataset <- cbind(
    lon = c(0, 1, 2, 3),
    lat = c(0, 0, 0, 0)
  )
  query <- c(0, 0)
  
  # 1 degree at equator is ~111 km
  result <- geodesic_nn_radius(dataset, query, radius = 250000)  # 250 km
  
  # Should include points at 0 and 1 degree (0 and ~111 km)
  expect_true(1 %in% result[[1]]$index)
  expect_true(2 %in% result[[1]]$index)
  # Point at 2 degrees (~222 km) should also be included
  expect_true(3 %in% result[[1]]$index)
  # Point at 3 degrees (~333 km) should be excluded
  expect_false(4 %in% result[[1]]$index)
})

test_that("geodesic_nn_radius returns empty for zero radius at non-dataset point", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  query <- c(5, 5)
  
  result <- geodesic_nn_radius(dataset, query, radius = 0)
  expect_equal(nrow(result[[1]]), 0)
})

test_that("geodesic_nn_radius returns list of correct length", {
  dataset <- cbind(lon = c(0, 10, 20), lat = c(0, 10, 20))
  queries <- cbind(lon = c(0, 10), lat = c(0, 10))
  
  result <- geodesic_nn_radius(dataset, queries, radius = 1e6)
  expect_length(result, 2)
})

test_that("geodesic_nn handles NA in query", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  queries <- cbind(lon = c(0, NA), lat = c(0, 5))
  
  result <- geodesic_nn(dataset, queries, k = 1)
  expect_false(is.na(result$index[1, 1]))
  expect_true(is.na(result$index[1, 2]))
})

test_that("geodesic_nn_radius handles NA in query", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  queries <- cbind(lon = c(0, NA), lat = c(0, 5))
  
  result <- geodesic_nn_radius(dataset, queries, radius = 1e6)
  expect_gt(nrow(result[[1]]), 0)
  expect_equal(nrow(result[[2]]), 0)
})

test_that("geodesic_nn works with single point dataset", {
  dataset <- c(151.21, -33.87)
  query <- c(144.96, -37.81)
  
  result <- geodesic_nn(dataset, query, k = 1)
  expect_equal(result$index[1, 1], 1L)
  expect_gt(result$distance[1, 1], 0)
})

test_that("geodesic_nn errors on invalid k", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  expect_error(geodesic_nn(dataset, c(0, 0), k = 0))
  expect_error(geodesic_nn(dataset, c(0, 0), k = -1))
})

test_that("geodesic_nn_radius errors on invalid radius", {
  dataset <- cbind(lon = c(0, 10), lat = c(0, 10))
  expect_error(geodesic_nn_radius(dataset, c(0, 0), radius = -1))
  expect_error(geodesic_nn_radius(dataset, c(0, 0), radius = c(100, 200)))
})

test_that("geodesic_nn self-search returns identity first", {
  dataset <- cbind(
    lon = c(151.21, 144.96, 153.03),
    lat = c(-33.87, -37.81, -27.47)
  )
  
  # Search dataset against itself
  result <- geodesic_nn(dataset, dataset, k = 1)
  
  # First neighbor of each point should be itself
  expect_equal(result$index[1, ], 1:3)
  # Distance to self should be 0
  expect_equal(as.vector(result$distance), c(0, 0, 0), tolerance = 1e-6)
})

test_that("geodesic_nn returns sorted by distance", {
  dataset <- cbind(
    lon = c(0, 5, 10, 15, 20),
    lat = c(0, 0, 0, 0, 0)
  )
  query <- c(0, 0)
  
  result <- geodesic_nn(dataset, query, k = 5)
  
  # Distances should be in ascending order
  dists <- result$distance[, 1]
  expect_equal(dists, sort(dists))
})

Try the geographiclib package in your browser

Any scripts or data that you put into this service are public.

geographiclib documentation built on March 4, 2026, 9:07 a.m.