test_that("s2_centroid() works", { expect_wkt_equal(s2_centroid("POINT (30 10)"), "POINT (30 10)") expect_true(s2_is_empty(s2_centroid("POINT EMPTY"))) expect_wkt_equal(s2_centroid("MULTIPOINT ((0 0), (0 10))"), "POINT (0 5)") expect_wkt_equal(s2_centroid("LINESTRING (0 0, 0 10)"), "POINT (0 5)", precision = 15) expect_near( s2_distance( s2_centroid("POLYGON ((-5 -5, 5 -5, 5 5, -5 5, -5 -5))"), "POINT (0 0)" ), 0, epsilon = 1e-6 ) }) test_that("s2_centroid() and s2_centroid_agg() normalize points", { expect_equal( s2_distance( s2_centroid("MULTIPOINT (1 1, 1 1)"), "POINT (1 1)" ), 0 ) expect_equal( s2_distance( s2_centroid_agg(c("POINT (1 1)", "POINT (1 1)")), "POINT (1 1)" ), 0 ) }) test_that("s2_point_on_surface() works", { expect_wkt_equal(s2_point_on_surface("POINT (30 10)"), "POINT (30 10)") expect_true(s2_is_empty(s2_point_on_surface("POINT EMPTY"))) expect_wkt_equal( s2_point_on_surface("POLYGON ((0 0, 10 0, 1 1, 0 10, 0 0))"), "POINT (0.4502368024893488 0.4502229020796313)", precision = 15 ) expect_wkt_equal( s2_point_on_surface("MULTIPOINT ((0 0), (0 5), (0 10))"), "POINT (0 5)" ) }) test_that("s2_boundary() works", { expect_true(s2_is_empty(s2_boundary("POINT (30 10)"))) expect_true(s2_is_empty(s2_boundary("POINT EMPTY"))) expect_true(s2_is_empty(s2_boundary("POLYGON EMPTY"))) expect_wkt_equal(s2_boundary("LINESTRING (0 0, 0 10)"), "MULTIPOINT ((0 0), (0 10))") expect_wkt_equal( s2_boundary("MULTIPOLYGON ( ((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)) )"), "MULTILINESTRING ( (40 40, 20 45, 45 30, 40 40), (20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20) )", precision = 15 ) }) test_that("s2_closest_point() works", { expect_wkt_equal(s2_closest_point("POINT (0 1)", "POINT (30 10)"), "POINT (0 1)") expect_wkt_equal(s2_closest_point("LINESTRING (0 1, -12 -12)", "POINT (30 10)"), "POINT (0 1)") }) test_that("s2_minimum_clearance_line_between() works", { expect_wkt_equal( s2_minimum_clearance_line_between("POINT (0 1)", "POINT (30 10)"), "LINESTRING (0 1, 30 10)" ) expect_true(s2_is_empty(s2_minimum_clearance_line_between("POINT (30 10)", "POINT EMPTY"))) expect_wkt_equal( s2_minimum_clearance_line_between("LINESTRING (0 1, -12 -12)", "POINT (30 10)"), "LINESTRING (0 1, 30 10)" ) expect_wkt_equal( s2_minimum_clearance_line_between("LINESTRING (0 0, 1 1)", "LINESTRING (1 0, 0 1)"), "MULTIPOINT ((0.5 0.500057), (0.5 0.500057))", precision = 6 ) }) test_that("s2_difference() works", { expect_wkt_equal(s2_difference("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)") expect_true(s2_is_empty(s2_difference("POINT (30 10)", "POINT (30 10)"))) expect_true(s2_is_empty(s2_difference("LINESTRING (0 0, 45 0)", "LINESTRING (0 0, 45 0)"))) }) test_that("s2_difference() works for polygons", { # on Windows i386, these fail without snap rounding df <- s2_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", s2_options(snap = s2_snap_level(30)) ) expect_near( s2_area(df, radius = 1), s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) - s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1), epsilon = 0.004 ) df0 <- s2_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "open", snap = s2_snap_level(30)) ) df1 <- s2_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "semi-open", snap = s2_snap_level(30)) ) df2 <- s2_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "closed", snap = s2_snap_level(30)) ) expect_equal(s2_area(df0) - s2_area(df2), 0.0) expect_equal(s2_area(df0) - s2_area(df1), 0.0) }) test_that("s2_sym_difference() works", { expect_wkt_equal(s2_sym_difference("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)") expect_true(s2_is_empty(s2_sym_difference("POINT (30 10)", "POINT (30 10)"))) expect_wkt_equal(s2_sym_difference("POINT (30 10)", "POINT (30 20)"), "MULTIPOINT ((30 20), (30 10))") expect_true(s2_is_empty(s2_sym_difference("LINESTRING (0 0, 45 0)", "LINESTRING (0 0, 45 0)"))) }) test_that("s2_sym_difference() works for polygons", { # on Windows i386, these fail without snap rounding df <- s2_sym_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", s2_options(snap = s2_snap_level(30)) ) expect_near( s2_area(df, radius = 1), 2 * s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) - s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1), epsilon = 0.0042 ) df0 <- s2_sym_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "open", snap = s2_snap_level(30)) ) df1 <- s2_sym_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "semi-open", snap = s2_snap_level(30)) ) df2 = s2_sym_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", s2_options(model = "closed", snap = s2_snap_level(30)) ) expect_equal(s2_area(df0) - s2_area(df2), 0.0) expect_equal(s2_area(df0) - s2_area(df1), 0.0) }) test_that("s2_intersection() works", { expect_wkt_equal(s2_intersection("POINT (30 10)", "POINT (30 10)"), "POINT (30 10)") expect_true(s2_is_empty(s2_intersection("POINT (30 10)", "POINT (30 11)"))) expect_wkt_equal( s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "LINESTRING (0 5, 10 5)" ), "LINESTRING (0 5, 10 5)" ) expect_equal( s2_distance( s2_intersection("LINESTRING (-45 0, 45 0)", "LINESTRING (0 -10, 0 10)"), "POINT (0 0)" ), 0 ) }) test_that("s2_intersction() works for polygons", { expect_wkt_equal( s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", s2_options(snap = s2_snap_level(30)) ), "POLYGON ((5 5, 10 5, 10 10, 5 10, 5 5))", precision = 2 ) expect_true(s2_is_empty(s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)"))) expect_true( s2_is_empty( s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "open") ) ) ) expect_true( s2_is_empty( s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "semi-open")) ) ) expect_wkt_equal( s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "closed")), "POINT(0 0)" ) df0 <- s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "open") ) df1 <- s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "semi-open") ) df2 <- s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "closed") ) expect_equal(s2_area(df0) - s2_area(df2), 0.0) expect_equal(s2_area(df0) - s2_area(df1), 0.0) }) test_that("s2_union(x) works", { expect_wkt_equal(s2_union("POINT (30 10)"), "POINT (30 10)") expect_wkt_equal(s2_union("POINT EMPTY"), "GEOMETRYCOLLECTION EMPTY") expect_wkt_equal( s2_union("MULTILINESTRING ((-45 0, 0 0), (0 0, 0 10))"), "LINESTRING (-45 0, 0 0, 0 10)" ) expect_wkt_equal(s2_union("GEOMETRYCOLLECTION (POINT (30 10))"), "POINT (30 10)") expect_wkt_equal( s2_union("GEOMETRYCOLLECTION (POINT (30 10), LINESTRING (0 0, 0 1))"), "GEOMETRYCOLLECTION (POINT (30 10), LINESTRING (0 0, 0 1))" ) }) test_that("s2_union(x) works with empty input", { expect_identical( s2_as_text(s2_union("MULTIPOLYGON EMPTY")), "GEOMETRYCOLLECTION EMPTY" ) }) test_that("s2_union(x) works with polygons that have overlapping input regions", { # two outer loops txt <- "MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)), ((0.1 0.9, 0.1 1.9, 1.1 1.9, 1.1 0.9, 0.1 0.9)))" # geos::geos_unary_union(txt) %>% as_wkb() %>% s2_area(radius = 1) unioned <- s2_union(as_s2_geography(txt, check = F)) expect_equal(round(s2_area(unioned, radius = 1), 12), 0.00058172748) # two outer loops, one valid inner loop # geos::geos_unary_union(txt2) %>% as_wkb() %>% s2_area(radius = 1) txt2 <- "MULTIPOLYGON ( ((0 0, 0 1, 1 1, 1 0, 0 0), (0.1 0.1, 0.5 0.1, 0.5 0.5, 0.1 0.5, 0.1 0.1)), ((0.1 0.9, 0.1 1.9, 1.1 1.9, 1.1 0.9, 0.1 0.9)) )" unioned <- s2_union(as_s2_geography(txt2, check = F)) expect_equal(round(s2_area(unioned, radius = 1), 12), 0.000532989259) }) test_that("s2_union(x) errors for the case of mixed dimension collections", { expect_error( s2_union( c("GEOMETRYCOLLECTION(POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10)), LINESTRING (0 -20, 0 20))") ), "for multidimensional collections not implemented" ) }) test_that("s2_union(x, y) works", { expect_wkt_equal(s2_union("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)") expect_wkt_equal(s2_union("POINT EMPTY", "POINT EMPTY"), "GEOMETRYCOLLECTION EMPTY") # LINESTRING (-45 0, 0 0, 0 10) expect_wkt_equal( s2_union("LINESTRING (-45 0, 0 0)", "LINESTRING (0 0, 0 10)"), "LINESTRING (-45 0, 0 0, 0 10)" ) }) test_that("s2_union() works for polygons", { # on Windows i386, these fail without snap rounding u <- s2_union( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", s2_options(snap = s2_snap_level(30)) ) u0 <- s2_union( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "open", snap = s2_snap_level(30)) ) u1 <- s2_union( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "semi-open", snap = s2_snap_level(30)) ) u2 <- s2_union( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" , s2_options(model = "closed", snap = s2_snap_level(30)) ) expect_equal(s2_area(u0) - s2_area(u2), 0.0) expect_equal(s2_area(u0) - s2_area(u1), 0.0) expect_near( s2_area(u, radius = 1), s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) + s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1) - s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1), epsilon = 0.004 ) }) test_that("binary operations use layer creation options", { expect_wkt_equal( s2_union( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", options = s2_options(polyline_type = "path", polyline_sibling_pairs = "discard") ), "LINESTRING (0 0, 0 1, 0 2, 0 3)" ) expect_true( s2_is_collection( s2_union( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", options = s2_options(polyline_type = "walk") ) ) ) expect_wkt_equal( s2_coverage_union_agg( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", options = s2_options(polyline_type = "path", polyline_sibling_pairs = "discard") ), "LINESTRING (0 0, 0 1, 0 2, 0 3)" ) expect_true( s2_is_collection( s2_coverage_union_agg( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", options = s2_options(polyline_type = "walk") ) ) ) }) test_that("s2_coverage_union_agg() works", { expect_wkt_equal(s2_coverage_union_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)") expect_wkt_equal(s2_coverage_union_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY") # NULL handling expect_identical( s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = FALSE), as_s2_geography(NA_character_) ) expect_wkt_equal( s2_coverage_union_agg(character()), as_s2_geography("GEOMETRYCOLLECTION EMPTY") ) expect_wkt_equal( s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = TRUE), "POINT (30 10)" ) }) test_that("s2_union_agg() works", { expect_wkt_equal(s2_union_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)") expect_wkt_equal(s2_union_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY") # NULL handling expect_identical( s2_union_agg(c("POINT (30 10)", NA), na.rm = FALSE), as_s2_geography(NA_character_) ) expect_wkt_equal( s2_union_agg(character()), as_s2_geography("GEOMETRYCOLLECTION EMPTY") ) expect_wkt_equal( s2_union_agg(c("POINT (30 10)", NA), na.rm = TRUE), "POINT (30 10)" ) # make sure this works on polygons since they are handled differently than # points and linestrings expect_equal( s2_area(s2_union_agg(s2_data_countries())), sum(s2_area(s2_union_agg(s2_data_countries()))) ) # check non-polygons and polygons together points_and_poly <- s2_union_agg( c( s2_data_countries(), s2_data_cities() ) ) points <- s2_rebuild(points_and_poly, options = s2_options(dimensions = "point")) poly <- s2_rebuild(points_and_poly, options = s2_options(dimensions = "polygon")) expect_false(any(s2_intersects(points, poly))) }) test_that("s2_rebuild_agg() works", { expect_wkt_equal(s2_rebuild_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)") expect_wkt_equal(s2_rebuild_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY") # NULL handling expect_identical( s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = FALSE), as_s2_geography(NA_character_) ) expect_wkt_equal( s2_rebuild_agg(character()), as_s2_geography("GEOMETRYCOLLECTION EMPTY") ) expect_wkt_equal( s2_rebuild_agg(c("POINT (30 10)", NA), na.rm = TRUE), "POINT (30 10)" ) }) test_that("s2_centroid_agg() works", { expect_wkt_equal(s2_centroid_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)") expect_wkt_equal(s2_centroid_agg(c("POINT EMPTY", "POINT EMPTY")), "POINT EMPTY") expect_wkt_equal(s2_centroid_agg(c("POINT (0 0)", "POINT (0 10)")), "POINT (0 5)", precision = 15) # NULL handling expect_identical( s2_centroid_agg(c("POINT (30 10)", NA), na.rm = FALSE), as_s2_geography(NA_character_) ) expect_wkt_equal( s2_centroid_agg(c("POINT (30 10)", NA), na.rm = TRUE), "POINT (30 10)" ) }) test_that("s2_snap_to_grid() works", { expect_wkt_equal( s2_as_text(s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2)), "POINT (0.33 0.67)", precision = 6 ) }) test_that("s2_buffer() works", { # create a hemisphere! ply <- s2_buffer_cells("POINT (0 0)", distance = pi / 2, radius = 1) expect_near(s2_area(ply, radius = 1), 4 * pi / 2, epsilon = 0.1) }) test_that("s2_simplify() works", { expect_wkt_equal( s2_simplify("LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)", tolerance = 100), "LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)" ) expect_wkt_equal( s2_simplify("LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)", tolerance = 1000), "LINESTRING (0 0, 0 3)" ) }) test_that("s2_rebuild() works", { s2_rebuild("POINT (-64 45)") s2_rebuild("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") s2_rebuild("GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 0 0))") # duplicated edges expect_wkt_equal( s2_rebuild("MULTIPOINT (-64 45, -64 45)", options = s2_options(duplicate_edges = FALSE)), "POINT (-64 45)" ) expect_wkt_equal( s2_rebuild("MULTIPOINT (-64 45, -64 45)", options = s2_options(duplicate_edges = TRUE)), "MULTIPOINT (-64 45, -64 45)" ) # crossing edges expect_true( s2_is_collection( s2_rebuild( "LINESTRING (0 -5, 0 5, -5 0, 5 0)", options = s2_options(split_crossing_edges = TRUE) ) ) ) # snap expect_wkt_equal( s2_rebuild( "MULTIPOINT (0.01 0.01, -0.01 -0.01)", options = s2_options( snap = s2_snap_precision(1e1), duplicate_edges = TRUE ) ), "MULTIPOINT ((0 0), (0 0))" ) # snap radius expect_wkt_equal( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 3)", options = s2_options( snap_radius = 1.5 * pi / 180 ) ), "LINESTRING (0 0, 0 2)" ) # simplify edge chains expect_wkt_equal( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 3)", options = s2_options( snap_radius = 0.01, simplify_edge_chains = TRUE ) ), "LINESTRING (0 0, 0 3)" ) # validate bad_poly <- s2_geog_from_text( "POLYGON ((0 0, 1.0 0, 1.0 1.0, -0.1 1.0, 1.1 0, 0 0))", check = FALSE ) expect_wkt_equal( s2_rebuild(bad_poly, options = s2_options(validate = FALSE)), bad_poly ) expect_error( s2_rebuild(bad_poly, options = s2_options(validate = TRUE)), "Edge 1 crosses edge 3" ) # polyline type expect_wkt_equal( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", s2_options(polyline_type = "walk") ), "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)" ) expect_true( s2_is_collection( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", s2_options(polyline_type = "path") ) ) ) # sibling edge pairs expect_true( s2_is_collection( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", s2_options(polyline_type = "path", polyline_sibling_pairs = "keep") ) ) ) expect_false( s2_is_collection( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", s2_options(polyline_type = "path", polyline_sibling_pairs = "discard") ) ) ) # dimension expect_true( s2_is_empty( s2_rebuild( "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)", s2_options(dimensions = c("point", "polygon")) ) ) ) }) test_that("real data survives the S2BooleanOperation", { # the 32-bit Solaris build results in some of the roundtripped # edges becoming degenerate. Rather than pass check = FALSE to # as_s2_geography(), just skip this on Solaris skip_on_os("solaris") for (continent in unique(s2::s2_data_tbl_countries$continent)) { # this is primarily a test of the S2BooleanOperation -> Geography constructor unioned <- expect_s3_class(s2_coverage_union_agg(s2_data_countries(continent)), "s2_geography") # this is a test of RGeography::Export() on potentially complex polygons exported <- expect_length(s2_as_binary(unioned), 1) # the output WKB should load as a polygon with oriented = TRUE and result in the # same number of points and similar area reloaded <- s2_geog_from_wkb(exported, oriented = TRUE) expect_equal(s2_num_points(reloaded), s2_num_points(unioned)) expect_equal(s2_area(reloaded, radius = 1), s2_area(unioned, radius = 1)) # also check with oriented = FALSE (may catch quirky nesting) reloaded <- s2_geog_from_wkb(exported, oriented = FALSE) expect_equal(s2_num_points(reloaded), s2_num_points(unioned)) expect_equal(s2_area(reloaded, radius = 1), s2_area(unioned, radius = 1)) } }) test_that("s2_interpolate() and s2_interpolate_normalized() work", { expect_identical( s2_as_text( s2_interpolate_normalized("LINESTRING (0 0, 0 60)", c(0, 0.25, 0.75, 1, NA)), precision = 5 ), c("POINT (0 0)", "POINT (0 15)", "POINT (0 45)", "POINT (0 60)", NA) ) expect_identical( s2_as_text( s2_interpolate("LINESTRING (0 0, 0 60)", c(0, 0.25, 0.75, 1, NA) * pi / 3, radius = 1), precision = 5 ), c("POINT (0 0)", "POINT (0 15)", "POINT (0 45)", "POINT (0 60)", NA) ) expect_error( s2_interpolate_normalized("POINT (0 1)", 1), "must be a polyline" ) expect_error( s2_interpolate_normalized("MULTILINESTRING ((0 1, 1 1), (1 1, 1 2))", 1), "must be a simple geography" ) }) test_that("s2_convex_hull() works", { expect_equal( s2_area(s2_convex_hull( c("GEOMETRYCOLLECTION(POINT(3.6 43.2), POINT (0 0), POINT(3.61 43.21))", NA) )), s2_area(c("POLYGON ((0 0, 3.61 43.21, 3.6 43.2, 0 0))", NA)) ) }) test_that("s2_convex_hull_agg() works", { expect_equal( s2_area(s2_convex_hull_agg(c("POINT(3.6 43.2)", "POINT (0 0)", "POINT(3.61 43.21)"))), s2_area("POLYGON ((0 0, 3.61 43.21, 3.6 43.2, 0 0))") ) expect_equal( s2_area(s2_convex_hull_agg(c( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"))), s2_area("POLYGON ((0 0, 10 0, 15 5, 15 15, 5 15, 0 10, 0 0))") ) expect_equal( s2_area(s2_convex_hull_agg(c( "POINT (3.6 43.2)", "LINESTRING (3.49 43.05, 3.52 43.1, 3.38 43.2, 3.1 43.1)", "POLYGON ((3.01 43.2, 3.4 44.01, 3.5 43.5, 3.1 43.2, 3.01 43.2))", "GEOMETRYCOLLECTION EMPTY" ))), s2_area( "POLYGON ((3.49 43.05, 3.6 43.2, 3.4 44.01, 3.01 43.2, 3.1 43.1, 3.49 43.05))" ) ) expect_equal( s2_area(s2_convex_hull_agg( "GEOMETRYCOLLECTION(POLYGON ((3.01 43.2, 3.4 44.01, 3.5 43.5, 3.1 43.2, 3.01 43.2)), POINT (3.6 43.2))" )), s2_area(s2_convex_hull_agg( c( "POLYGON ((3.01 43.2, 3.4 44.01, 3.5 43.5, 3.1 43.2, 3.01 43.2))", "POINT (3.6 43.2)" ) )) ) expect_identical( s2_convex_hull_agg(c("POINT (0 0)", NA), na.rm = FALSE), as_s2_geography(NA_character_) ) expect_equal( s2_area(s2_convex_hull_agg(c("POINT (0 0)", NA), na.rm = TRUE)), 0 ) })