Skip to content

Commit 7863e48

Browse files
committed
Add id_format and axis_order options for grid ID output; update tests and docs for new ID formatting features
1 parent 2713b48 commit 7863e48

5 files changed

Lines changed: 232 additions & 11 deletions

File tree

R/inspire_grid_from_ids.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ inspire_grid_from_ids <- function(
2929
point_type = c("llc", "centroid"),
3030
output_type = c("sf_polygons", "sf_points", "dataframe"),
3131
include_llc = TRUE,
32+
id_format = c("both", "long", "short"),
33+
axis_order = c("NE", "EN"),
3234
quiet = FALSE,
3335
dsn = NULL,
3436
layer = NULL,
@@ -48,6 +50,8 @@ inspire_grid_from_ids <- function(
4850
point_type = point_type,
4951
output_type = output_type,
5052
include_llc = include_llc,
53+
id_format = id_format,
54+
axis_order = axis_order,
5155
dsn = dsn,
5256
layer = layer,
5357
quiet = quiet

R/inspire_grid_from_ids_internal.R

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ inspire_grid_from_ids_internal <- function(
33
point_type = c("llc", "centroid"),
44
output_type = c("sf_polygons", "sf_points", "dataframe"),
55
include_llc = TRUE,
6+
id_format = c("both", "long", "short"),
7+
axis_order = c("NE", "EN"),
68
quiet = FALSE,
79
dsn = NULL,
810
layer = NULL,
911
...
1012
) {
1113
output_type <- match.arg(output_type)
1214
point_type <- match.arg(point_type)
15+
id_format <- match.arg(id_format)
16+
axis_order <- match.arg(axis_order)
1317

1418
if (!requireNamespace("sf", quietly = TRUE)) {
1519
stop("The 'sf' package is required. Please install it.", call. = FALSE)
@@ -56,6 +60,44 @@ inspire_grid_from_ids_internal <- function(
5660
}
5761

5862
cellsize <- grid_df$cellsize[[1]]
63+
epsg_code <- grid_crs$epsg %||% 3035
64+
65+
# Detect input format (long IDs start with "CRS")
66+
input_is_long <- all(startsWith(ids, "CRS"))
67+
68+
# Helper to convert/format IDs based on id_format and axis_order
69+
format_output_ids <- function(input_ids, id_format, axis_order, epsg) {
70+
if (id_format == "long") {
71+
if (input_is_long) {
72+
list(GRD_ID = input_ids)
73+
} else {
74+
list(GRD_ID = inspire_id_format(input_ids, crs = epsg))
75+
}
76+
} else if (id_format == "short") {
77+
if (input_is_long) {
78+
list(GRD_ID = inspire_id_format(input_ids, axis_order = axis_order))
79+
} else {
80+
# Input is short - convert to long first, then back to short with desired axis_order
81+
long_ids <- inspire_id_format(input_ids, crs = epsg)
82+
list(GRD_ID = inspire_id_format(long_ids, axis_order = axis_order))
83+
}
84+
} else {
85+
# id_format == "both"
86+
if (input_is_long) {
87+
list(
88+
GRD_ID_LONG = input_ids,
89+
GRD_ID_SHORT = inspire_id_format(input_ids, axis_order = axis_order)
90+
)
91+
} else {
92+
long_ids <- inspire_id_format(input_ids, crs = epsg)
93+
short_ids <- inspire_id_format(long_ids, axis_order = axis_order)
94+
list(
95+
GRD_ID_LONG = long_ids,
96+
GRD_ID_SHORT = short_ids
97+
)
98+
}
99+
}
100+
}
59101

60102
# --- 1. In-Memory Generation (dsn is NULL) ---
61103
if (is.null(dsn)) {
@@ -67,8 +109,11 @@ inspire_grid_from_ids_internal <- function(
67109
point_type = point_type
68110
)
69111

70-
# Add ID (Specific to this function)
71-
out_obj$id <- ids
112+
# Add IDs with proper format and column names
113+
formatted_ids <- format_output_ids(ids, id_format, axis_order, epsg_code)
114+
for (col_name in names(formatted_ids)) {
115+
out_obj[[col_name]] <- formatted_ids[[col_name]]
116+
}
72117

73118
# Cleanup and reorder using helper
74119
return(clean_and_order_grid(
@@ -118,7 +163,11 @@ inspire_grid_from_ids_internal <- function(
118163
point_type = point_type
119164
)
120165

121-
chunk_obj$id <- chunk_ids
166+
# Add IDs with proper format and column names
167+
formatted_ids <- format_output_ids(chunk_ids, id_format, axis_order, epsg_code)
168+
for (col_name in names(formatted_ids)) {
169+
chunk_obj[[col_name]] <- formatted_ids[[col_name]]
170+
}
122171

123172
# Use helper for consistency
124173
chunk_obj <- clean_and_order_grid(

man/inspire_grid.Rd

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-inspire_grid_from_ids.R

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@ test_that("inspire_grid_from_ids_internal produces correct output types", {
44
"CRS3035RES1000mN3501000E4400000"
55
)
66

7-
# Test sf_polygons output
7+
# Test sf_polygons output (default id_format = "both")
88
grid_poly <- inspire_grid_from_ids_internal(ids, output_type = "sf_polygons")
99
expect_s3_class(grid_poly, "sf")
1010
expect_true(inherits(st_geometry(grid_poly), "sfc_POLYGON"))
1111
expect_equal(nrow(grid_poly), 2)
12-
expect_true("id" %in% names(grid_poly))
12+
expect_true(all(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_poly)))
1313
expect_equal(st_crs(grid_poly), st_crs(3035))
1414

1515
# Test sf_points output
1616
grid_pts <- inspire_grid_from_ids_internal(ids, output_type = "sf_points")
1717
expect_s3_class(grid_pts, "sf")
1818
expect_true(inherits(st_geometry(grid_pts), "sfc_POINT"))
1919
expect_equal(nrow(grid_pts), 2)
20-
expect_true("id" %in% names(grid_pts))
20+
expect_true(all(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_pts)))
2121
expect_equal(st_crs(grid_pts), st_crs(3035))
2222

2323
# Test dataframe output
2424
grid_df <- inspire_grid_from_ids_internal(ids, output_type = "dataframe")
2525
expect_s3_class(grid_df, "data.frame")
2626
expect_equal(nrow(grid_df), 2)
27-
expect_true("id" %in% names(grid_df))
27+
expect_true(all(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_df)))
2828
expect_true(all(
2929
c("X_LLC", "Y_LLC", "X_centroid", "Y_centroid") %in% names(grid_df)
3030
))
@@ -166,7 +166,7 @@ test_that("Round-trip: grid from extent -> short IDs -> grid from IDs matches or
166166
# The regenerated grid should have the same cell positions
167167
# Sort both by short ID to ensure proper comparison
168168
grid_original_sorted <- grid_original[order(grid_original$GRD_ID), ]
169-
grid_regenerated_sorted <- grid_regenerated[order(grid_regenerated$id), ]
169+
grid_regenerated_sorted <- grid_regenerated[order(grid_regenerated$GRD_ID_SHORT), ]
170170

171171
# Compare LLC coordinates (these should match exactly)
172172
expect_equal(
@@ -216,3 +216,169 @@ test_that("Short IDs with explicit CRS parameter do not produce warnings", {
216216
expect_s3_class(grid_with_crs, "sf")
217217
expect_equal(st_crs(grid_with_crs), st_crs(TARGET_CRS))
218218
})
219+
220+
test_that("id_format = 'long' produces long format IDs", {
221+
# From long input IDs
222+
long_ids <- c(
223+
"CRS3035RES1000mN3500000E4400000",
224+
"CRS3035RES1000mN3501000E4400000"
225+
)
226+
227+
grid_long <- inspire_grid_from_ids_internal(
228+
long_ids,
229+
output_type = "sf_polygons",
230+
id_format = "long"
231+
)
232+
233+
expect_true("GRD_ID" %in% names(grid_long))
234+
expect_false(any(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_long)))
235+
expect_true(all(startsWith(grid_long$GRD_ID, "CRS")))
236+
expect_equal(grid_long$GRD_ID, long_ids)
237+
238+
# From short input IDs - should convert to long
239+
short_ids <- c("1kmN3500E4400", "1kmN3501E4400")
240+
241+
expect_warning(
242+
grid_from_short <- inspire_grid_from_ids_internal(
243+
short_ids,
244+
output_type = "sf_polygons",
245+
id_format = "long"
246+
),
247+
regexp = "CRS not specified"
248+
)
249+
250+
expect_true("GRD_ID" %in% names(grid_from_short))
251+
expect_true(all(startsWith(grid_from_short$GRD_ID, "CRS")))
252+
})
253+
254+
test_that("id_format = 'short' produces short format IDs", {
255+
# From long input IDs
256+
long_ids <- c(
257+
"CRS3035RES1000mN3500000E4400000",
258+
"CRS3035RES1000mN3501000E4400000"
259+
)
260+
261+
grid_short <- inspire_grid_from_ids_internal(
262+
long_ids,
263+
output_type = "sf_polygons",
264+
id_format = "short"
265+
)
266+
267+
expect_true("GRD_ID" %in% names(grid_short))
268+
expect_false(any(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_short)))
269+
expect_false(any(startsWith(grid_short$GRD_ID, "CRS")))
270+
# Default axis_order is "NE", so IDs should start with "1kmN"
271+
expect_true(all(startsWith(grid_short$GRD_ID, "1kmN")))
272+
})
273+
274+
test_that("id_format = 'both' produces both long and short format IDs", {
275+
long_ids <- c(
276+
"CRS3035RES1000mN3500000E4400000",
277+
"CRS3035RES1000mN3501000E4400000"
278+
)
279+
280+
grid_both <- inspire_grid_from_ids_internal(
281+
long_ids,
282+
output_type = "sf_polygons",
283+
id_format = "both"
284+
)
285+
286+
expect_true(all(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(grid_both)))
287+
expect_false("GRD_ID" %in% names(grid_both))
288+
expect_true(all(startsWith(grid_both$GRD_ID_LONG, "CRS")))
289+
expect_false(any(startsWith(grid_both$GRD_ID_SHORT, "CRS")))
290+
})
291+
292+
test_that("axis_order = 'EN' produces E...N format short IDs", {
293+
long_ids <- c(
294+
"CRS3035RES1000mN3500000E4400000",
295+
"CRS3035RES1000mN3501000E4400000"
296+
)
297+
298+
# Test with id_format = "short"
299+
grid_en <- inspire_grid_from_ids_internal(
300+
long_ids,
301+
output_type = "sf_polygons",
302+
id_format = "short",
303+
axis_order = "EN"
304+
)
305+
306+
expect_true("GRD_ID" %in% names(grid_en))
307+
# IDs should start with "1kmE" (not "1kmN")
308+
expect_true(all(startsWith(grid_en$GRD_ID, "1kmE")))
309+
expect_true(all(grepl("E[0-9]+N[0-9]+$", grid_en$GRD_ID)))
310+
311+
# Test with id_format = "both"
312+
grid_both_en <- inspire_grid_from_ids_internal(
313+
long_ids,
314+
output_type = "sf_polygons",
315+
id_format = "both",
316+
axis_order = "EN"
317+
)
318+
319+
expect_true(all(startsWith(grid_both_en$GRD_ID_SHORT, "1kmE")))
320+
})
321+
322+
test_that("axis_order = 'NE' produces N...E format short IDs (default)", {
323+
long_ids <- c(
324+
"CRS3035RES1000mN3500000E4400000",
325+
"CRS3035RES1000mN3501000E4400000"
326+
)
327+
328+
grid_ne <- inspire_grid_from_ids_internal(
329+
long_ids,
330+
output_type = "sf_polygons",
331+
id_format = "short",
332+
axis_order = "NE"
333+
)
334+
335+
expect_true("GRD_ID" %in% names(grid_ne))
336+
# IDs should start with "1kmN" (not "1kmE")
337+
expect_true(all(startsWith(grid_ne$GRD_ID, "1kmN")))
338+
expect_true(all(grepl("N[0-9]+E[0-9]+$", grid_ne$GRD_ID)))
339+
})
340+
341+
test_that("axis_order converts short IDs between NE and EN formats", {
342+
# Input short IDs in NE format
343+
short_ids_ne <- c("1kmN3500E4400", "1kmN3501E4400")
344+
345+
expect_warning(
346+
grid_to_en <- inspire_grid_from_ids_internal(
347+
short_ids_ne,
348+
output_type = "sf_polygons",
349+
id_format = "short",
350+
axis_order = "EN"
351+
),
352+
regexp = "CRS not specified"
353+
)
354+
355+
# Should convert NE -> Long -> EN
356+
expect_true(all(startsWith(grid_to_en$GRD_ID, "1kmE")))
357+
expect_equal(grid_to_en$GRD_ID, c("1kmE4400N3500", "1kmE4400N3501"))
358+
})
359+
360+
test_that("inspire_grid S3 generic passes id_format and axis_order correctly", {
361+
long_ids <- c(
362+
"CRS3035RES1000mN3500000E4400000",
363+
"CRS3035RES1000mN3501000E4400000"
364+
)
365+
366+
# Test via S3 generic with id_format = "long"
367+
grid_long <- inspire_grid(
368+
x = long_ids,
369+
id_format = "long"
370+
)
371+
372+
expect_true("GRD_ID" %in% names(grid_long))
373+
expect_true(all(startsWith(grid_long$GRD_ID, "CRS")))
374+
375+
# Test via S3 generic with id_format = "short" and axis_order = "EN"
376+
grid_short_en <- inspire_grid(
377+
x = long_ids,
378+
id_format = "short",
379+
axis_order = "EN"
380+
)
381+
382+
expect_true("GRD_ID" %in% names(grid_short_en))
383+
expect_true(all(startsWith(grid_short_en$GRD_ID, "1kmE")))
384+
})

tests/testthat/test-write_to_disk.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ test_that("inspire_grid_from_ids writes dataframe to CSV correctly (with chunkin
194194

195195
expect_true(file.exists(tmp_csv))
196196

197-
# Check content
197+
# Check content (default id_format = "both" produces GRD_ID_LONG and GRD_ID_SHORT)
198198
df_in <- readr::read_csv(tmp_csv, show_col_types = FALSE)
199199
expect_equal(nrow(df_in), 2)
200-
expect_true("id" %in% names(df_in))
201-
expect_equal(df_in$id, ids)
200+
expect_true(all(c("GRD_ID_LONG", "GRD_ID_SHORT") %in% names(df_in)))
201+
expect_equal(df_in$GRD_ID_LONG, ids)
202202
})
203203

204204
test_that("inspire_grid_from_extent streams to CSV (dropping geometry)", {

0 commit comments

Comments
 (0)