tests/testthat/test-polygonarea.R

test_that("polygon_area works with single polygon", {
  # Triangle: London - New York - Rio de Janeiro
  pts <- cbind(
    lon = c(0, -74, -43),
    lat = c(52, 41, -23)
  )
  result <- polygon_area(pts)

  expect_type(result, "list")
  expect_named(result, c("area", "perimeter", "n"))
  expect_equal(result$n, 3)
  expect_true(is.numeric(result$area))
  expect_true(is.numeric(result$perimeter))
  expect_true(result$perimeter > 0)
})

test_that("polygon_area accepts different input formats", {
  pts_matrix <- cbind(c(0, -74, -43), c(52, 41, -23))
  pts_df <- data.frame(lon = c(0, -74, -43), lat = c(52, 41, -23))
  pts_list <- list(lon = c(0, -74, -43), lat = c(52, 41, -23))

  result1 <- polygon_area(pts_matrix)
  result2 <- polygon_area(pts_df)
  result3 <- polygon_area(pts_list)

  expect_equal(result1$area, result2$area)
  expect_equal(result1$area, result3$area)
  expect_equal(result1$perimeter, result2$perimeter)
})

test_that("polygon_area handles multiple polygons with id", {
  pts <- cbind(
    lon = c(0, -74, -43, 100, 110, 105),
    lat = c(52, 41, -23, 10, 10, 20)
  )
  result <- polygon_area(pts, id = c(1, 1, 1, 2, 2, 2))

  expect_s3_class(result, "data.frame")
  expect_named(result, c("id", "area", "perimeter", "n"))
  expect_equal(nrow(result), 2)
  expect_equal(result$id, c(1, 2))
  expect_equal(result$n, c(3, 3))
})

test_that("polygon_area gives correct sign for winding direction", {
  # Counter-clockwise polygon (positive area)
  ccw <- cbind(
    lon = c(0, 1, 1, 0),
    lat = c(0, 0, 1, 1)
  )
  # Clockwise polygon (negative area)
  cw <- cbind(
    lon = c(0, 0, 1, 1),
    lat = c(0, 1, 1, 0)
  )

  result_ccw <- polygon_area(ccw)
  result_cw <- polygon_area(cw)

  # Areas should be opposite signs
  expect_true(sign(result_ccw$area) != sign(result_cw$area))

  # Absolute areas should be equal
  expect_equal(abs(result_ccw$area), abs(result_cw$area), tolerance = 1e-6)
})

test_that("polygon_area computes polyline length", {
  pts <- cbind(
    lon = c(0, 1, 2),
    lat = c(0, 0, 0)
  )

  result <- polygon_area(pts, polyline = TRUE)

  expect_true(result$perimeter > 0)
  # For a polyline, area is not meaningful but should still be returned
  expect_true(is.numeric(result$area))
})

test_that("polygon_area rejects too few points", {
  expect_error(polygon_area(cbind(0, 0)), "at least 3 points")
  expect_error(polygon_area(cbind(c(0, 1), c(0, 1))), "at least 3 points")
})

test_that("polygon_area polyline accepts 2 points", {
  pts <- cbind(c(0, 1), c(0, 0))
  result <- polygon_area(pts, polyline = TRUE)
  expect_equal(result$n, 2)
})


test_that("polygon_area gives reasonable values for known polygon", {
  # Approximate 1 degree x 1 degree square at equator
  # Should be roughly 111km x 111km = ~12,321 km²
  square <- cbind(
    lon = c(0, 1, 1, 0),
    lat = c(0, 0, 1, 1)
  )
  result <- polygon_area(square)

  area_km2 <- abs(result$area) / 1e6
  # Should be approximately 12,321 km² (allowing some tolerance)
  expect_true(area_km2 > 12000 && area_km2 < 12500)

  # Perimeter should be roughly 4 * 111km = 444 km
  perim_km <- result$perimeter / 1000
  expect_true(perim_km > 440 && perim_km < 450)
})

test_that("polygon_area_cumulative returns correct structure", {
  pts <- cbind(
    lon = c(0, -74, -43, 28),
    lat = c(52, 41, -23, -26)
  )
  result <- polygon_area_cumulative(pts)

  expect_s3_class(result, "data.frame")
  expect_named(result, c("lon", "lat", "area", "perimeter"))
  expect_equal(nrow(result), 4)
  expect_equal(result$lon, pts[, 1])
  expect_equal(result$lat, pts[, 2])
})

test_that("polygon_area_cumulative shows accumulating values", {
  pts <- cbind(
    lon = c(0, 1, 1, 0),
    lat = c(0, 0, 1, 1)
  )
  result <- polygon_area_cumulative(pts)

  # Perimeter should generally increase (or stay same) as points added
  # Area magnitude should generally increase
  expect_true(all(diff(abs(result$perimeter)) >= 0))
})

test_that("polygon_area handles large polygons",
          {
            # Hemisphere-scale polygon
            pts <- cbind(
              lon = c(-180, 0, 180, 0),
              lat = c(0, 45, 0, -45)
            )
            result <- polygon_area(pts)

            # Should complete without error and return valid numbers

            expect_true(is.finite(result$area))
            expect_true(is.finite(result$perimeter))
            expect_true(result$perimeter > 0)
          })

test_that("polygon_area works with many polygons", {
  # 100 triangles
  n_polys <- 100
  lon <- runif(n_polys * 3, -180, 180)
  lat <- runif(n_polys * 3, -60, 60)
  id <- rep(1:n_polys, each = 3)

  pts <- cbind(lon, lat)
  result <- polygon_area(pts, id = id)

  expect_equal(nrow(result), n_polys)
  expect_equal(result$id, 1:n_polys)
  expect_true(all(result$n == 3))
  expect_true(all(is.finite(result$area)))
  expect_true(all(result$perimeter > 0))
})

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.