From 2baaec75525dea97b7f0bda5beeed52036469608 Mon Sep 17 00:00:00 2001 From: Roger Bivand Date: Thu, 12 Sep 2024 10:54:24 +0200 Subject: [PATCH 01/43] create clean voronoi point order PR #1371 #2426 --- NEWS.md | 2 ++ R/geom-transformers.R | 30 +++++++++++++++++++++++------- man/geos_unary.Rd | 14 ++++++++++++-- src/geos.cpp | 3 +++ tests/geos.R | 14 +++++++++++++- tests/geos.Rout.save | 22 +++++++++++++++++----- 6 files changed, 70 insertions(+), 15 deletions(-) diff --git a/NEWS.md b/NEWS.md index 12add0430..c0d276a6f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # version 1.0-18 +* add flag for preservation of point order in `st_voronoi` #1371 for GEOS >= 3.12 + * fix build failure with GDAL < 3.4.0 #2436 # version 1.0-17 diff --git a/R/geom-transformers.R b/R/geom-transformers.R index af13a68e3..f29e67696 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -450,6 +450,7 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) { #' @name geos_unary #' @export #' @param envelope object of class \code{sfc} or \code{sfg} containing a \code{POLYGON} with the envelope for a voronoi diagram; this only takes effect when it is larger than the default envelope, chosen when \code{envelope} is an empty polygon +#' @param point_order logical; preserve point order if TRUE and GEOS version >= 3.12; overrides bOnlyEdges #' @details \code{st_voronoi} creates voronoi tesselation. \code{st_voronoi} requires GEOS version 3.5 or above #' @examples #' set.seed(1) @@ -470,24 +471,39 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) { #' # compute Voronoi polygons: #' pols = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts)))) #' # match them to points: -#' pts$pols = pols[unlist(st_intersects(pts, pols))] +#' pts_pol = st_intersects(pts, pols) +#' pts$pols = pols[unlist(pts_pol)] # re-order +#' if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, +#' silent = TRUE))) { +#' pols_po = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts)), +#' point_order = TRUE)) # GEOS >= 3.12 can preserve order of inputs +#' pts_pol_po = st_intersects(pts, pols_po) +#' print(all(unlist(pts_pol_po) == 1:(n/2))) +#' } #' plot(pts["id"], pch = 16) # ID is color #' plot(st_set_geometry(pts, "pols")["id"], xlim = c(0,1), ylim = c(0,1), reset = FALSE) #' plot(st_geometry(pts), add = TRUE) #' layout(matrix(1)) # reset plot layout #' } -st_voronoi = function(x, envelope, dTolerance = 0.0, bOnlyEdges = FALSE) +st_voronoi = function(x, envelope, dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) UseMethod("st_voronoi") #' @export -st_voronoi.sfg = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE) - get_first_sfg(st_voronoi(st_sfc(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges)) +st_voronoi.sfg = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) + get_first_sfg(st_voronoi(st_sfc(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges, point_order = point_order)) #' @export -st_voronoi.sfc = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE) { +st_voronoi.sfc = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) { if (compareVersion(CPL_geos_version(), "3.5.0") > -1) { if (isTRUE(st_is_longlat(x))) warning("st_voronoi does not correctly triangulate longitude/latitude data") + if (compareVersion(CPL_geos_version(), "3.12.0") > -1) { + bOnlyEdges = as.integer(bOnlyEdges) + if (point_order) bOnlyEdges = 2L # GEOS enum GEOS_VORONOI_PRESERVE_ORDER + } else { + if (point_order) + warning("Point order retention not supported for GEOS ", CPL_geos_version()) + } st_sfc(CPL_geos_voronoi(x, st_sfc(envelope), dTolerance = dTolerance, bOnlyEdges = as.integer(bOnlyEdges))) } else @@ -495,8 +511,8 @@ st_voronoi.sfc = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdg } #' @export -st_voronoi.sf = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE) { - st_set_geometry(x, st_voronoi(st_geometry(x), st_sfc(envelope), dTolerance, bOnlyEdges)) +st_voronoi.sf = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) { + st_set_geometry(x, st_voronoi(st_geometry(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges, point_order = point_order)) } #' @name geos_unary diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index 0041b1510..e9c4ca8c1 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -49,7 +49,7 @@ st_inscribed_circle(x, dTolerance, ...) st_minimum_rotated_rectangle(x, ...) -st_voronoi(x, envelope, dTolerance = 0, bOnlyEdges = FALSE) +st_voronoi(x, envelope, dTolerance = 0, bOnlyEdges = FALSE, point_order = FALSE) st_polygonize(x) @@ -120,6 +120,8 @@ meters.} \item{of_largest_polygon}{logical; for \code{st_centroid}: if \code{TRUE}, return centroid of the largest (sub)polygon of a \code{MULTIPOLYGON} rather than of the whole \code{MULTIPOLYGON}} \item{dfMaxLength}{maximum length of a line segment. If \code{x} has geographical coordinates (long/lat), \code{dfMaxLength} is either a numeric expressed in meter, or an object of class \code{units} with length units \code{rad} or \code{degree}; segmentation in the long/lat case takes place along the great circle, using \link[lwgeom:geod]{st_geod_segmentize}.} + +\item{point_order}{logical; preserve point order if TRUE and GEOS version >= 3.12; overrides bOnlyEdges} } \value{ an object of the same class of \code{x}, with manipulated geometry. @@ -278,7 +280,15 @@ if (compareVersion(sf_extSoftVersion()[["GEOS"]], "3.5.0") > -1) { # compute Voronoi polygons: pols = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts)))) # match them to points: - pts$pols = pols[unlist(st_intersects(pts, pols))] + pts_pol = st_intersects(pts, pols) + pts$pols = pols[unlist(pts_pol)] # re-order + if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, + silent = TRUE))) { + pols_po = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts)), + point_order = TRUE)) # GEOS >= 3.12 can preserve order of inputs + pts_pol_po = st_intersects(pts, pols_po) + print(all(unlist(pts_pol_po) == 1:(n/2))) + } plot(pts["id"], pch = 16) # ID is color plot(st_set_geometry(pts, "pols")["id"], xlim = c(0,1), ylim = c(0,1), reset = FALSE) plot(st_geometry(pts), add = TRUE) diff --git a/src/geos.cpp b/src/geos.cpp index 703cf1d6a..5846d6952 100644 --- a/src/geos.cpp +++ b/src/geos.cpp @@ -35,6 +35,9 @@ # if GEOS_VERSION_MINOR >= 11 # define HAVE311 # endif +# if GEOS_VERSION_MINOR >= 12 +# define HAVE312 +# endif #else # if GEOS_VERSION_MAJOR > 3 # define HAVE340 diff --git a/tests/geos.R b/tests/geos.R index ccce312be..376f14abb 100644 --- a/tests/geos.R +++ b/tests/geos.R @@ -73,7 +73,8 @@ st_line_merge(mls) if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.5.0") > -1, silent = TRUE))) { # voronoi: set.seed(1) - x = st_multipoint(matrix(runif(10),,2)) + m = matrix(runif(10),,2) + x = st_multipoint(m) box = st_polygon(list(rbind(c(0,0),c(1,0),c(1,1),c(0,1),c(0,0)))) v = st_sfc(st_voronoi(x, st_sfc(box))) plot(v, col = 0, border = 1, axes = TRUE) @@ -81,6 +82,17 @@ if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.5.0") > -1, silent plot(x, add = TRUE, col = 'red', cex=2, pch=16) plot(st_intersection(st_cast(v), box)) # clip to smaller box plot(x, add = TRUE, col = 'red', cex=2, pch=16) + v0 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box))) + pal <- c("black", "red", "green", "blue", "orange") + opar = par(mfrow=c(1,2)) + plot(st_collection_extract(v0, "POLYGON"), col=pal) + text(m[,1], m[,2], label=1:5, col="white") + if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, silent = TRUE))) { + v2 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box), point_order=TRUE)) + plot(st_collection_extract(v2, "POLYGON"), col=pal) + text(m[,1], m[,2], label=1:5, col="white") + } + par(opar) v = st_voronoi(x) print(class(v)) diff --git a/tests/geos.Rout.save b/tests/geos.Rout.save index 5d0092256..303390bf9 100644 --- a/tests/geos.Rout.save +++ b/tests/geos.Rout.save @@ -1,7 +1,7 @@ -R version 4.2.2 Patched (2022-11-10 r83330) -- "Innocent and Trusting" -Copyright (C) 2022 The R Foundation for Statistical Computing -Platform: x86_64-pc-linux-gnu (64-bit) +R version 4.4.1 (2024-06-14) -- "Race for Your Life" +Copyright (C) 2024 The R Foundation for Statistical Computing +Platform: x86_64-pc-linux-gnu R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. @@ -162,7 +162,8 @@ LINESTRING (0 0, 1 1, 2 0) > if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.5.0") > -1, silent = TRUE))) { + # voronoi: + set.seed(1) -+ x = st_multipoint(matrix(runif(10),,2)) ++ m = matrix(runif(10),,2) ++ x = st_multipoint(m) + box = st_polygon(list(rbind(c(0,0),c(1,0),c(1,1),c(0,1),c(0,0)))) + v = st_sfc(st_voronoi(x, st_sfc(box))) + plot(v, col = 0, border = 1, axes = TRUE) @@ -170,6 +171,17 @@ LINESTRING (0 0, 1 1, 2 0) + plot(x, add = TRUE, col = 'red', cex=2, pch=16) + plot(st_intersection(st_cast(v), box)) # clip to smaller box + plot(x, add = TRUE, col = 'red', cex=2, pch=16) ++ v0 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box))) ++ pal <- c("black", "red", "green", "blue", "orange") ++ opar = par(mfrow=c(1,2)) ++ plot(st_collection_extract(v0, "POLYGON"), col=pal) ++ text(m[,1], m[,2], label=1:5, col="white") ++ if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, silent = TRUE))) { ++ v2 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box), point_order=TRUE)) ++ plot(st_collection_extract(v2, "POLYGON"), col=pal) ++ text(m[,1], m[,2], label=1:5, col="white") ++ } ++ par(opar) + + v = st_voronoi(x) + print(class(v)) @@ -666,4 +678,4 @@ CRS: NA > > proc.time() user system elapsed - 19.725 0.860 19.747 + 11.890 0.081 12.018 From bcfa3c9310de104e55aa6206e65eea58c8f24bbc Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 9 Oct 2024 17:52:51 +0200 Subject: [PATCH 02/43] update url --- R/read.R | 2 +- man/st_read.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/read.R b/R/read.R index bcf52e6b6..95255d5f1 100644 --- a/R/read.R +++ b/R/read.R @@ -61,7 +61,7 @@ set_utf8 = function(x) { #' and if necessary corrected (when seen from above: exterior ring counter #' clockwise, holes clockwise) #' @details for \code{geometry_column}, see also -#' \url{https://trac.osgeo.org/gdal/wiki/rfc41_multiple_geometry_fields} +#' \url{https://gdal.org/en/latest/development/rfc/rfc41_multiple_geometry_fields.html} #' #' for values for \code{type} see #' \url{https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary}, but diff --git a/man/st_read.Rd b/man/st_read.Rd index fe4bb7753..3af7123c4 100644 --- a/man/st_read.Rd +++ b/man/st_read.Rd @@ -127,7 +127,7 @@ Well-Know Binary geometries to sfc } \details{ for \code{geometry_column}, see also -\url{https://trac.osgeo.org/gdal/wiki/rfc41_multiple_geometry_fields} +\url{https://gdal.org/en/latest/development/rfc/rfc41_multiple_geometry_fields.html} for values for \code{type} see \url{https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary}, but From 157c0174dcbe855777691fd7d5c22db6488226fc Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 9 Oct 2024 18:56:50 +0200 Subject: [PATCH 03/43] tidy tests --- tests/crs.R | 5 ----- tests/crs.Rout.save | 9 +-------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/crs.R b/tests/crs.R index f36871f07..0dfaf8494 100644 --- a/tests/crs.R +++ b/tests/crs.R @@ -30,11 +30,6 @@ suppressWarnings( sf_project("+proj=longlat", "+proj=lcc +lat_1=30 +lat_2=60", cbind(c(0,0),c(-80,-90)), keep = TRUE) ) st_transform(st_sfc(st_point(c(0,0)), st_point(c(1,1)), crs = 4326), 3857) -if (Sys.getenv("USER") %in% c("edzer", "travis")) { # causes memory leaks: - stopifnot(inherits(try(sf_project("+proj=longlat", "+proj=bar", matrix(1:4,2)), silent = TRUE), "try-error")) - stopifnot(inherits(try(sf_project("+proj=foo", "+proj=longlat", matrix(1:4,2)), silent = TRUE), "try-error")) -} - if (sf_extSoftVersion()["USE_PROJ_H"] == "true" || sf_proj_info("have_datum_files")) { "datum files installed" } else { diff --git a/tests/crs.Rout.save b/tests/crs.Rout.save index 1747b30cd..22ff8f448 100644 --- a/tests/crs.Rout.save +++ b/tests/crs.Rout.save @@ -70,13 +70,6 @@ Bounding box: xmin: 0 ymin: 0 xmax: 111319.5 ymax: 111325.1 Projected CRS: WGS 84 / Pseudo-Mercator POINT (0 0) POINT (111319.5 111325.1) -> if (Sys.getenv("USER") %in% c("edzer", "travis")) { # causes memory leaks: -+ stopifnot(inherits(try(sf_project("+proj=longlat", "+proj=bar", matrix(1:4,2)), silent = TRUE), "try-error")) -+ stopifnot(inherits(try(sf_project("+proj=foo", "+proj=longlat", matrix(1:4,2)), silent = TRUE), "try-error")) -+ } -proj_create: Error 1027 (Invalid value for an argument): Unknown projection -proj_create: Error 1027 (Invalid value for an argument): Unknown projection -> > if (sf_extSoftVersion()["USE_PROJ_H"] == "true" || sf_proj_info("have_datum_files")) { + "datum files installed" + } else { @@ -100,4 +93,4 @@ proj_create: Error 1027 (Invalid value for an argument): Unknown projection > > proc.time() user system elapsed - 0.626 1.357 0.510 + 0.750 1.093 0.700 From ac53d506d02048435fa61ddf644ffdb391040757 Mon Sep 17 00:00:00 2001 From: edzer Date: Fri, 11 Oct 2024 10:59:52 +0200 Subject: [PATCH 04/43] bump version --- DESCRIPTION | 2 +- NEWS.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 433ecd9cf..524b856a2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: sf -Version: 1.0-18 +Version: 1.0-19 Title: Simple Features for R Authors@R: c(person(given = "Edzer", diff --git a/NEWS.md b/NEWS.md index cd37ca584..c3246e1e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# version 1.0-19 + # version 1.0-18 * support `POLYGON FULL` simple feature geometry, representing the the entire Earth surface, as used by `s2geometry`; #2441 From 61ddb58d4d54d4f52ae2162488eca8e6bebd85e2 Mon Sep 17 00:00:00 2001 From: Matthieu Viry Date: Tue, 15 Oct 2024 13:15:33 +0200 Subject: [PATCH 05/43] Fix typo in vignette 7 --- vignettes/sf7.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/sf7.Rmd b/vignettes/sf7.Rmd index 030ddda47..d074b4d30 100644 --- a/vignettes/sf7.Rmd +++ b/vignettes/sf7.Rmd @@ -340,7 +340,7 @@ excessive simplification (bottom right). Note that buffers created with s2 _alwa follow s2 cell boundaries, they are never smooth. Hence, choosing a large number for `max_cells` leads to seemingly smooth but, zoomed in, very complex buffers. -To achieve a similar result you could first transform thes result and then use `sf::st_buffer()`. A simple benchmark shows the +To achieve a similar result you could first transform the result and then use `sf::st_buffer()`. A simple benchmark shows the computational efficiency of the `s2` geometry engine in comparison with transforming and then creating buffers: From 1fa29ceec7520ba6063394a88fc81a4c33e976cf Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 15 Oct 2024 21:54:21 +0200 Subject: [PATCH 06/43] fixes #2414 --- R/geom-transformers.R | 3 +-- man/geos_unary.Rd | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/R/geom-transformers.R b/R/geom-transformers.R index adb238bb7..bf737ff76 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -19,7 +19,7 @@ #' @param mitreLimit numeric; limit of extension for a join if \code{joinStyle} 'MITRE' is used (default 1.0, minimum 0.0); see details #' @param singleSide logical; if \code{TRUE}, single-sided buffers are returned for linear geometries, #' in which case negative \code{dist} values give buffers on the right-hand side, positive on the left; see details -#' @param ... passed on to [s2::s2_buffer_cells()] +#' @param ... in `st_buffer` passed on to [s2::s2_buffer_cells()], otherwise ignored #' @return an object of the same class of \code{x}, with manipulated geometry. #' @export #' @details \code{st_buffer} computes a buffer around this geometry/each geometry. If any of \code{endCapStyle}, @@ -698,7 +698,6 @@ st_node.sf = function(x) { #' @details \code{st_segmentize} adds points to straight lines #' @export #' @param dfMaxLength maximum length of a line segment. If \code{x} has geographical coordinates (long/lat), \code{dfMaxLength} is either a numeric expressed in meter, or an object of class \code{units} with length units \code{rad} or \code{degree}; segmentation in the long/lat case takes place along the great circle, using \link[lwgeom:geod]{st_geod_segmentize}. -#' @param ... ignored #' @examples #' sf = st_sf(a=1, geom=st_sfc(st_linestring(rbind(c(0,0),c(1,1)))), crs = 4326) #' if (require(lwgeom, quietly = TRUE)) { diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index 0041b1510..684e64eb1 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -89,7 +89,7 @@ numeric \code{dist} is assumed to have the units of the coordinates, and a \code \item{singleSide}{logical; if \code{TRUE}, single-sided buffers are returned for linear geometries, in which case negative \code{dist} values give buffers on the right-hand side, positive on the left; see details} -\item{...}{ignored} +\item{...}{in \code{st_buffer} passed on to \code{\link[s2:s2_boundary]{s2::s2_buffer_cells()}}, otherwise ignored} \item{ratio}{numeric; fraction convex: 1 returns the convex hulls, 0 maximally concave hulls} From f0eb794e1fe3286d2a1243cf7162cd14b4fc0327 Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 16 Oct 2024 13:20:19 +0200 Subject: [PATCH 07/43] up to gdal 3.10.0beta1 --- inst/docker/gdal/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inst/docker/gdal/Dockerfile b/inst/docker/gdal/Dockerfile index 37a0044dd..d6d82bc7b 100644 --- a/inst/docker/gdal/Dockerfile +++ b/inst/docker/gdal/Dockerfile @@ -100,9 +100,10 @@ RUN cd proj* \ # && cd - # GDAL: -ENV GDAL_VERSION 3.9.2 -ENV GDAL_VERSION_NAME 3.9.2 +ENV GDAL_VERSION 3.10.0 +ENV GDAL_VERSION_NAME 3.10.0beta1 #https://download.osgeo.org/gdal/3.9.0/gdal-3.9.0beta1.tar.gz +#https://download.osgeo.org/gdal/3.10.0/gdal-3.10.0beta1.tar.gz RUN wget -q http://download.osgeo.org/gdal/${GDAL_VERSION}/gdal-${GDAL_VERSION_NAME}.tar.gz \ && tar -xf gdal-${GDAL_VERSION_NAME}.tar.gz \ From 395fef682654c705f14a67ff65fb015e20d5bb28 Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 16 Oct 2024 13:20:39 +0200 Subject: [PATCH 08/43] use GDALRasterBand::InterpolateAtPoint() if GDAL >= 3.10.0 --- src/stars.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/stars.cpp b/src/stars.cpp index 423a952c9..3671154a5 100644 --- a/src/stars.cpp +++ b/src/stars.cpp @@ -778,6 +778,11 @@ NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpol if (iPixel < 0 || iLine < 0 || iPixel >= xsize || iLine >= ysize) // outside bbox: pixel = NA_REAL; else { // read pixel: +#if GDAL_VERSION_NUM >= 3100000 + if (poBand->InterpolateAtPoint(Pixel, Line, interpolate ? GRIORA_NearestNeighbour : GRIORA_Bilinear, &pixel, nullptr) != CE_None) + // tbd: handle GRIORA_Cubic, GRIORA_CubicSpline + stop("Error in InterpolateAtPoint()"); +#else if (interpolate) // stop("interpolate not implemented"); pixel = get_bilinear(poBand, Pixel, Line, iPixel, iLine, @@ -785,6 +790,7 @@ NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpol else if (GDALRasterIO(poBand, GF_Read, iPixel, iLine, 1, 1, &pixel, 1, 1, GDT_CFloat64, 0, 0) != CE_None) stop("Error reading!"); +#endif if (nodata_set && pixel == nodata) pixel = NA_REAL; else if (dfOffset != 0.0 || dfScale != 1.0) From b8e12d888ebb40852e129cc7ed43c35c8c7177d0 Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 16 Oct 2024 21:56:08 +0200 Subject: [PATCH 09/43] use InterpolateAtPoint when GDAL >= 3.10.0 --- R/RcppExports.R | 2 +- R/stars.R | 7 ++++--- man/gdal.Rd | 9 +++++++-- src/RcppExports.cpp | 4 ++-- src/stars.cpp | 28 ++++++++++++++++++++-------- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index f4d9d07d3..57a366b3c 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -393,7 +393,7 @@ CPL_write_gdal <- function(x, fname, driver, options, Type, dims, from, gt, p4s, invisible(.Call(`_sf_CPL_write_gdal`, x, fname, driver, options, Type, dims, from, gt, p4s, na_val, scale_offset, create, only_create)) } -CPL_extract <- function(input, xy, interpolate = FALSE) { +CPL_extract <- function(input, xy, interpolate) { .Call(`_sf_CPL_extract`, input, xy, interpolate) } diff --git a/R/stars.R b/R/stars.R index 4d171b164..7085c31e7 100644 --- a/R/stars.R +++ b/R/stars.R @@ -340,9 +340,10 @@ gdal_rasterize = function(sf, x, gt, file, driver = "GTiff", options = character #' @rdname gdal #' @param f gdal raster data source filename #' @param pts points matrix -#' @param bilinear logical; use bilinear interpolation, rather than nearest neighbor? -gdal_extract = function(f, pts, bilinear = FALSE) { - CPL_extract(f, pts, as.logical(bilinear)) +#' @param resampling character; resampling method; for method cubic or cubicspline, +#' `stars_proxy` objects should be used and GDAL should have version >= 3.10.0 +gdal_extract = function(f, pts, resampling = c("nearest", "bilinear", "cubic", "cubicspline")) { + CPL_extract(f, pts, match.arg(resampling)) } #' @rdname gdal diff --git a/man/gdal.Rd b/man/gdal.Rd index 8d682dfa0..6d70c6861 100644 --- a/man/gdal.Rd +++ b/man/gdal.Rd @@ -68,7 +68,11 @@ gdal_polygonize( gdal_rasterize(sf, x, gt, file, driver = "GTiff", options = character()) -gdal_extract(f, pts, bilinear = FALSE) +gdal_extract( + f, + pts, + resampling = c("nearest", "bilinear", "cubic", "cubicspline") +) gdal_read_mdim( file, @@ -147,7 +151,8 @@ gdal_create(f, nxy, values, crs, xlim, ylim) \item{pts}{points matrix} -\item{bilinear}{logical; use bilinear interpolation, rather than nearest neighbor?} +\item{resampling}{character; resampling method; for method cubic or cubicspline, +\code{stars_proxy} objects should be used and GDAL should have version >= 3.10.0} \item{array_name}{array name} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 56586fa7a..039d37e11 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -1339,14 +1339,14 @@ BEGIN_RCPP END_RCPP } // CPL_extract -NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpolate); +NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, CharacterVector interpolate); RcppExport SEXP _sf_CPL_extract(SEXP inputSEXP, SEXP xySEXP, SEXP interpolateSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< CharacterVector >::type input(inputSEXP); Rcpp::traits::input_parameter< NumericMatrix >::type xy(xySEXP); - Rcpp::traits::input_parameter< bool >::type interpolate(interpolateSEXP); + Rcpp::traits::input_parameter< CharacterVector >::type interpolate(interpolateSEXP); rcpp_result_gen = Rcpp::wrap(CPL_extract(input, xy, interpolate)); return rcpp_result_gen; END_RCPP diff --git a/src/stars.cpp b/src/stars.cpp index 3671154a5..184baae29 100644 --- a/src/stars.cpp +++ b/src/stars.cpp @@ -721,8 +721,8 @@ double get_bilinear(GDALRasterBand *poBand, double Pixel, double Line, dY -= 0.5; // read: - if (GDALRasterIO(poBand, GF_Read, iPixel, iLine, 2, 2, - (void *) pixels, 2, 2, GDT_CFloat64, sizeof(double), 0) != CE_None) + if (poBand->RasterIO(GF_Read, iPixel, iLine, 2, 2, + (void *) pixels, 2, 2, GDT_CFloat64, sizeof(double), 0, NULL) != CE_None) stop("Error reading!"); // f(0,0): pixels[0], f(1,0): pixels[1], f(0,1): pixels[2], f(1,1): pixels[3] if (na_set && (pixels[0] == na_value || pixels[1] == na_value || @@ -736,7 +736,7 @@ double get_bilinear(GDALRasterBand *poBand, double Pixel, double Line, } // [[Rcpp::export]] -NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpolate = false) { +NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, CharacterVector interpolate) { // mostly taken from gdal/apps/gdallocationinfo.cpp GDALDataset *poDataset = (GDALDataset *) GDALOpenEx(input[0], GA_ReadOnly, @@ -749,6 +749,17 @@ NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpol NumericMatrix ret(xy.nrow(), poDataset->GetRasterCount()); int xsize = poDataset->GetRasterXSize(); int ysize = poDataset->GetRasterYSize(); + GDALRIOResampleAlg RA; + if (interpolate[0] == "nearest") + RA = GRIORA_NearestNeighbour; + else if (interpolate[0] == "bilinear") + RA = GRIORA_Bilinear; + else if (interpolate[0] == "cubic") + RA = GRIORA_Cubic; + else if (interpolate[0] == "cubicspline") + RA = GRIORA_CubicSpline; + else + stop("interpolation method not supported"); // #nocov double gt[6]; poDataset->GetGeoTransform(gt); @@ -779,16 +790,17 @@ NumericMatrix CPL_extract(CharacterVector input, NumericMatrix xy, bool interpol pixel = NA_REAL; else { // read pixel: #if GDAL_VERSION_NUM >= 3100000 - if (poBand->InterpolateAtPoint(Pixel, Line, interpolate ? GRIORA_NearestNeighbour : GRIORA_Bilinear, &pixel, nullptr) != CE_None) + if (poBand->InterpolateAtPoint(Pixel, Line, RA, &pixel, nullptr) != CE_None) // tbd: handle GRIORA_Cubic, GRIORA_CubicSpline stop("Error in InterpolateAtPoint()"); #else - if (interpolate) - // stop("interpolate not implemented"); + if (RA == GRIORA_Cubic || RA == GRIORA_CubicSpline) + stop("cubic or cubicspline requires GDAL >= 3.10.0"); + if (RA == GRIORA_Bilinear) pixel = get_bilinear(poBand, Pixel, Line, iPixel, iLine, xsize, ysize, nodata_set, nodata); - else if (GDALRasterIO(poBand, GF_Read, iPixel, iLine, 1, 1, - &pixel, 1, 1, GDT_CFloat64, 0, 0) != CE_None) + else if (poBand->RasterIO(GF_Read, iPixel, iLine, 1, 1, + &pixel, 1, 1, GDT_CFloat64, 0, 0, NULL) != CE_None) stop("Error reading!"); #endif if (nodata_set && pixel == nodata) From f93f5658f7c7468dcdd346f61c89acd8068ad7ab Mon Sep 17 00:00:00 2001 From: edzer Date: Mon, 21 Oct 2024 13:15:47 +0200 Subject: [PATCH 10/43] fixes https://github.com/r-spatial/stars/issues/720 --- src/stars.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/stars.cpp b/src/stars.cpp index 184baae29..0afd7b4a8 100644 --- a/src/stars.cpp +++ b/src/stars.cpp @@ -695,27 +695,32 @@ double get_bilinear(GDALRasterBand *poBand, double Pixel, double Line, double pixels[4]; double dY = Line - iLine; // [0, 1) over a raster cell double dX = Pixel - iPixel; // [0, 1) over a raster cell - if ((dY < 0.5 && iLine > 0) || (iLine == RasterYSize - 1)) // where to start reading + double eps = 1.0e-13; + if ((dY < 0.5 && iLine > 0) || (iLine == RasterYSize - 1)) { // where to start reading iLine -= 1; - if ((dX < 0.5 && iPixel > 0) || (iPixel == RasterXSize - 1)) + dY += 1.0; + } + if ((dX < 0.5 && iPixel > 0) || (iPixel == RasterXSize - 1)) { iPixel -= 1; + dX += 1.0; + } // x: - if (Pixel < 0.5) // border: + if (Pixel < (0.5 - eps)) // border: dX = 0.0; - else if (Pixel > RasterXSize - 0.5) + else if (Pixel > (RasterXSize - 0.5 + eps)) dX = 1.0; - else if (dX < 0.5) // shift to pixel center: + else if (dX < (0.5 - eps)) // shift to pixel center: dX += 0.5; else dX -= 0.5; // y: - if (Line < 0.5) + if (Line < (0.5 - eps)) dY = 0.0; - else if (Line > RasterYSize - 0.5) + else if (Line > (RasterYSize - 0.5 + eps)) dY = 1.0; - else if (dY < 0.5) + else if (dY < (0.5 - eps)) dY += 0.5; else dY -= 0.5; @@ -724,6 +729,8 @@ double get_bilinear(GDALRasterBand *poBand, double Pixel, double Line, if (poBand->RasterIO(GF_Read, iPixel, iLine, 2, 2, (void *) pixels, 2, 2, GDT_CFloat64, sizeof(double), 0, NULL) != CE_None) stop("Error reading!"); + // Rprintf("px[%g (%g) %g (%g) %g (%g) %g (%g)] dY: %g dX: %g iLine: %d iPixel: %d Line: %g Pixel :%g\n", pixels[0], (1-dX)*(1-dY), pixels[1], dX * (1-dY), pixels[2], (1-dX) * dY, pixels[3], dX * dY, dY, dX, iLine, iPixel, Line, Pixel); + // // f(0,0): pixels[0], f(1,0): pixels[1], f(0,1): pixels[2], f(1,1): pixels[3] if (na_set && (pixels[0] == na_value || pixels[1] == na_value || pixels[2] == na_value || pixels[3] == na_value)) From 7d340b0435775fcdf0292622651d0ce84bff0693 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:53:17 +0200 Subject: [PATCH 11/43] fix typos --- R/geom-transformers.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/geom-transformers.R b/R/geom-transformers.R index bf737ff76..c34cd4372 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -25,7 +25,7 @@ #' @details \code{st_buffer} computes a buffer around this geometry/each geometry. If any of \code{endCapStyle}, #' \code{joinStyle}, or \code{mitreLimit} are set to non-default values ('ROUND', 'ROUND', 1.0 respectively) then #' the underlying 'buffer with style' GEOS function is used. -#' If a negative buffer returns empty polygons instead of shrinking, set sf_use_s2() to FALSE +#' If a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. #' See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} for details. #' #' \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and \code{singleSide} only @@ -313,7 +313,7 @@ st_simplify.sf = function(x, preserveTopology, dTolerance = 0.0) { #' @name geos_unary #' @export -#' @param bOnlyEdges logical; if TRUE, return lines, else return polygons +#' @param bOnlyEdges logical; if \code{TRUE}, return lines, else return polygons #' @details \code{st_triangulate} triangulates set of points (not constrained). \code{st_triangulate} requires GEOS version 3.4 or above st_triangulate = function(x, dTolerance = 0.0, bOnlyEdges = FALSE) UseMethod("st_triangulate") @@ -455,7 +455,7 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) { #' @name geos_unary #' @export #' @param envelope object of class \code{sfc} or \code{sfg} containing a \code{POLYGON} with the envelope for a voronoi diagram; this only takes effect when it is larger than the default envelope, chosen when \code{envelope} is an empty polygon -#' @details \code{st_voronoi} creates voronoi tesselation. \code{st_voronoi} requires GEOS version 3.5 or above +#' @details \code{st_voronoi} creates voronoi tessellation. \code{st_voronoi} requires GEOS version 3.5 or above #' @examples #' set.seed(1) #' x = st_multipoint(matrix(runif(10),,2)) @@ -505,7 +505,7 @@ st_voronoi.sf = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdge } #' @name geos_unary -#' @details \code{st_polygonize} creates polygon from lines that form a closed ring. In case of \code{st_polygonize}, \code{x} must be an object of class \code{LINESTRING} or \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these +#' @details \code{st_polygonize} creates a polygon from lines that form a closed ring. In case of \code{st_polygonize}, \code{x} must be an object of class \code{LINESTRING} or \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these #' @export #' @examples #' mls = st_multilinestring(list(matrix(c(0,0,0,1,1,1,0,0),,2,byrow=TRUE))) From f50409ea9c0eb6406eb7bee5d36b0de24e3c0912 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Tue, 22 Oct 2024 00:05:04 +0200 Subject: [PATCH 12/43] improve st_buffer() description --- R/geom-transformers.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/geom-transformers.R b/R/geom-transformers.R index c34cd4372..338535d93 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -22,15 +22,15 @@ #' @param ... in `st_buffer` passed on to [s2::s2_buffer_cells()], otherwise ignored #' @return an object of the same class of \code{x}, with manipulated geometry. #' @export -#' @details \code{st_buffer} computes a buffer around this geometry/each geometry. If any of \code{endCapStyle}, -#' \code{joinStyle}, or \code{mitreLimit} are set to non-default values ('ROUND', 'ROUND', 1.0 respectively) then -#' the underlying 'buffer with style' GEOS function is used. -#' If a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. -#' See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} for details. +#' @details \code{st_buffer} computes a buffer around this geometry/each geometry. Depending on the spatial +#' coordinate system, a different engine (GEOS or S2) can be used, which have different function +#' arguments. The \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and +#' \code{singleSide} parameters only work if the GEOS engine is used (i.e. projected coordinates or +#' when \code{sf_use_s2()} is set to \code{FALSE}). See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} +#' for details. The \code{max_cells} and \code{min_level} parameters ([s2::s2_buffer_cells()] ) work with the S2 +#' engine (i.e. geographic coordinates) and can be used to change the buffer shape (e.g. smoothing). If +#' a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. #' -#' \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and \code{singleSide} only -#' work when the GEOS back-end is used: for projected coordinates or when \code{sf_use_s2()} is set -#' to \code{FALSE}. #' @examples #' #' ## st_buffer, style options (taken from rgeos gBuffer) From 6da5a815416ddec68700005f426de1e33bf261a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Tue, 22 Oct 2024 00:50:59 +0200 Subject: [PATCH 13/43] regenerate docs --- man/geos_unary.Rd | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index 684e64eb1..caa284ba6 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -111,7 +111,7 @@ specified with long-lat coordinates and \code{sf_use_s2()} returns \code{TRUE}, then the value of \code{dTolerance} must be specified in meters.} -\item{bOnlyEdges}{logical; if TRUE, return lines, else return polygons} +\item{bOnlyEdges}{logical; if \code{TRUE}, return lines, else return polygons} \item{envelope}{object of class \code{sfc} or \code{sfg} containing a \code{POLYGON} with the envelope for a voronoi diagram; this only takes effect when it is larger than the default envelope, chosen when \code{envelope} is an empty polygon} @@ -128,15 +128,14 @@ an object of the same class of \code{x}, with manipulated geometry. Geometric unary operations on simple feature geometries. These are all generics, with methods for \code{sfg}, \code{sfc} and \code{sf} objects, returning an object of the same class. All operations work on a per-feature basis, ignoring all other features. } \details{ -\code{st_buffer} computes a buffer around this geometry/each geometry. If any of \code{endCapStyle}, -\code{joinStyle}, or \code{mitreLimit} are set to non-default values ('ROUND', 'ROUND', 1.0 respectively) then -the underlying 'buffer with style' GEOS function is used. -If a negative buffer returns empty polygons instead of shrinking, set sf_use_s2() to FALSE -See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} for details. - -\code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and \code{singleSide} only -work when the GEOS back-end is used: for projected coordinates or when \code{sf_use_s2()} is set -to \code{FALSE}. +\code{st_buffer} computes a buffer around this geometry/each geometry. Depending on the spatial +coordinate system, a different engine (GEOS or S2) can be used, which have different function +arguments. The \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and +\code{singleSide} parameters only work if the GEOS engine is used (i.e. projected coordinates or +when \code{sf_use_s2()} is set to \code{FALSE}). See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} +for details. The \code{max_cells} and \code{min_level} parameters (\code{\link[s2:s2_boundary]{s2::s2_buffer_cells()}} ) work with the S2 +engine (i.e. geographic coordinates) and can be used to change the buffer shape (e.g. smoothing). If +a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. \code{st_boundary} returns the boundary of a geometry @@ -162,9 +161,9 @@ rectangle has width equal to the minimum diameter, and a longer length. If the convex hill of the input is degenerate (a line or point) a linestring or point is returned. -\code{st_voronoi} creates voronoi tesselation. \code{st_voronoi} requires GEOS version 3.5 or above +\code{st_voronoi} creates voronoi tessellation. \code{st_voronoi} requires GEOS version 3.5 or above -\code{st_polygonize} creates polygon from lines that form a closed ring. In case of \code{st_polygonize}, \code{x} must be an object of class \code{LINESTRING} or \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these +\code{st_polygonize} creates a polygon from lines that form a closed ring. In case of \code{st_polygonize}, \code{x} must be an object of class \code{LINESTRING} or \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these \code{st_line_merge} merges lines. In case of \code{st_line_merge}, \code{x} must be an object of class \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these From 161d056cb45a12ea902a84d7fb382f582943e8e0 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Tue, 22 Oct 2024 01:02:01 +0200 Subject: [PATCH 14/43] remove space --- R/geom-transformers.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/geom-transformers.R b/R/geom-transformers.R index 338535d93..df709269a 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -27,7 +27,7 @@ #' arguments. The \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and #' \code{singleSide} parameters only work if the GEOS engine is used (i.e. projected coordinates or #' when \code{sf_use_s2()} is set to \code{FALSE}). See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} -#' for details. The \code{max_cells} and \code{min_level} parameters ([s2::s2_buffer_cells()] ) work with the S2 +#' for details. The \code{max_cells} and \code{min_level} parameters ([s2::s2_buffer_cells()]) work with the S2 #' engine (i.e. geographic coordinates) and can be used to change the buffer shape (e.g. smoothing). If #' a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. #' From 674a412c479a7faa63fedb92450682c8c6600ee9 Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 22 Oct 2024 10:51:22 +0200 Subject: [PATCH 15/43] docs --- man/geos_unary.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index caa284ba6..b467538c5 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -133,7 +133,7 @@ coordinate system, a different engine (GEOS or S2) can be used, which have diffe arguments. The \code{nQuadSegs}, \code{endCapsStyle}, \code{joinStyle}, \code{mitreLimit} and \code{singleSide} parameters only work if the GEOS engine is used (i.e. projected coordinates or when \code{sf_use_s2()} is set to \code{FALSE}). See \href{https://postgis.net/docs/ST_Buffer.html}{postgis.net/docs/ST_Buffer.html} -for details. The \code{max_cells} and \code{min_level} parameters (\code{\link[s2:s2_boundary]{s2::s2_buffer_cells()}} ) work with the S2 +for details. The \code{max_cells} and \code{min_level} parameters (\code{\link[s2:s2_boundary]{s2::s2_buffer_cells()}}) work with the S2 engine (i.e. geographic coordinates) and can be used to change the buffer shape (e.g. smoothing). If a negative buffer returns empty polygons instead of shrinking, set \code{sf_use_s2()} to \code{FALSE}. From a27e662c62428427d658a7e01177f9894322d15d Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 23 Oct 2024 12:53:02 +0200 Subject: [PATCH 16/43] address #2460 --- R/RcppExports.R | 4 ++-- R/gdal_utils.R | 6 ++++-- man/gdal_utils.Rd | 5 ++++- src/RcppExports.cpp | 9 +++++---- src/gdal_utils.cpp | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index 57a366b3c..3d8d0aa2b 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -117,8 +117,8 @@ CPL_gdalinfo <- function(obj, options, oo, co) { .Call(`_sf_CPL_gdalinfo`, obj, options, oo, co) } -CPL_ogrinfo <- function(obj, options, oo, co) { - .Call(`_sf_CPL_ogrinfo`, obj, options, oo, co) +CPL_ogrinfo <- function(obj, options, oo, co, read_only = FALSE) { + .Call(`_sf_CPL_ogrinfo`, obj, options, oo, co, read_only) } CPL_gdaladdo <- function(obj, method, overviews, bands, oo, co, clean = FALSE, read_only = FALSE) { diff --git a/R/gdal_utils.R b/R/gdal_utils.R index 36e8a827f..6fa1596df 100644 --- a/R/gdal_utils.R +++ b/R/gdal_utils.R @@ -31,6 +31,7 @@ resampling_method = function(option = "near") { #' @param quiet logical; if \code{TRUE}, suppress printing the output for \code{info} and \code{mdiminfo}, and suppress printing progress #' @param processing character; processing options for \code{demprocessing} #' @param colorfilename character; name of color file for \code{demprocessing} (mandatory if \code{processing="color-relief"}) +#' @param read_only logical; only for `ogrinfo`: if `TRUE`, source is opened in read-only mode #' @return \code{info} returns a character vector with the raster metadata; all other utils return (invisibly) a logical indicating success (i.e., \code{TRUE}); in case of failure, an error is raised. #' @export #' @seealso \link{gdal_addo} for adding overlays to a raster file; \link{st_layers} to query geometry type(s) and crs from layers in a (vector) data source @@ -76,7 +77,7 @@ gdal_utils = function(util = "info", source, destination, options = character(0) quiet = !(util %in% c("info", "gdalinfo", "ogrinfo", "vectorinfo", "mdiminfo")) || ("-multi" %in% options), processing = character(0), colorfilename = character(0), - config_options = character(0)) { + config_options = character(0), read_only = FALSE) { stopifnot(is.character(options), is.character(config_options)) if (!quiet && "-multi" %in% options) @@ -103,7 +104,8 @@ gdal_utils = function(util = "info", source, destination, options = character(0) ret = switch(util, gdalinfo =, info = CPL_gdalinfo(if (missing(source)) character(0) else source, options, oo, config_options), - vectorinfo =, ogrinfo = CPL_ogrinfo(if (missing(source)) character(0) else source, options, oo, config_options), + vectorinfo =, ogrinfo = CPL_ogrinfo(if (missing(source)) character(0) else source, options, oo, config_options, + isTRUE(read_only) || "-ro" %in% options), warp = CPL_gdalwarp(source, destination, options, oo, doo, config_options, quiet, "-overwrite" %in% options), warper = CPL_gdal_warper(source, destination, as.integer(resampling_method(options)), oo, doo, config_options, quiet), # nocov diff --git a/man/gdal_utils.Rd b/man/gdal_utils.Rd index f8cfef2e0..370392d31 100644 --- a/man/gdal_utils.Rd +++ b/man/gdal_utils.Rd @@ -13,7 +13,8 @@ gdal_utils( ("-multi" \%in\% options), processing = character(0), colorfilename = character(0), - config_options = character(0) + config_options = character(0), + read_only = FALSE ) } \arguments{ @@ -32,6 +33,8 @@ gdal_utils( \item{colorfilename}{character; name of color file for \code{demprocessing} (mandatory if \code{processing="color-relief"})} \item{config_options}{named character vector with GDAL config options, like \code{c(option1=value1, option2=value2)}} + +\item{read_only}{logical; only for \code{ogrinfo}: if \code{TRUE}, source is opened in read-only mode} } \value{ \code{info} returns a character vector with the raster metadata; all other utils return (invisibly) a logical indicating success (i.e., \code{TRUE}); in case of failure, an error is raised. diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 039d37e11..8dac5ea11 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -373,8 +373,8 @@ BEGIN_RCPP END_RCPP } // CPL_ogrinfo -Rcpp::CharacterVector CPL_ogrinfo(Rcpp::CharacterVector obj, Rcpp::CharacterVector options, Rcpp::CharacterVector oo, Rcpp::CharacterVector co); -RcppExport SEXP _sf_CPL_ogrinfo(SEXP objSEXP, SEXP optionsSEXP, SEXP ooSEXP, SEXP coSEXP) { +Rcpp::CharacterVector CPL_ogrinfo(Rcpp::CharacterVector obj, Rcpp::CharacterVector options, Rcpp::CharacterVector oo, Rcpp::CharacterVector co, bool read_only); +RcppExport SEXP _sf_CPL_ogrinfo(SEXP objSEXP, SEXP optionsSEXP, SEXP ooSEXP, SEXP coSEXP, SEXP read_onlySEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; @@ -382,7 +382,8 @@ BEGIN_RCPP Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type options(optionsSEXP); Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type oo(ooSEXP); Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type co(coSEXP); - rcpp_result_gen = Rcpp::wrap(CPL_ogrinfo(obj, options, oo, co)); + Rcpp::traits::input_parameter< bool >::type read_only(read_onlySEXP); + rcpp_result_gen = Rcpp::wrap(CPL_ogrinfo(obj, options, oo, co, read_only)); return rcpp_result_gen; END_RCPP } @@ -1510,7 +1511,7 @@ static const R_CallMethodDef CallEntries[] = { {"_sf_CPL_read_ogr", (DL_FUNC) &_sf_CPL_read_ogr, 14}, {"_sf_CPL_read_gdal_stream", (DL_FUNC) &_sf_CPL_read_gdal_stream, 12}, {"_sf_CPL_gdalinfo", (DL_FUNC) &_sf_CPL_gdalinfo, 4}, - {"_sf_CPL_ogrinfo", (DL_FUNC) &_sf_CPL_ogrinfo, 4}, + {"_sf_CPL_ogrinfo", (DL_FUNC) &_sf_CPL_ogrinfo, 5}, {"_sf_CPL_gdaladdo", (DL_FUNC) &_sf_CPL_gdaladdo, 8}, {"_sf_CPL_gdalwarp", (DL_FUNC) &_sf_CPL_gdalwarp, 8}, {"_sf_CPL_gdalrasterize", (DL_FUNC) &_sf_CPL_gdalrasterize, 8}, diff --git a/src/gdal_utils.cpp b/src/gdal_utils.cpp index 080e8f1f1..16f2a26b7 100644 --- a/src/gdal_utils.cpp +++ b/src/gdal_utils.cpp @@ -70,14 +70,14 @@ Rcpp::CharacterVector CPL_gdalinfo(Rcpp::CharacterVector obj, Rcpp::CharacterVec // [[Rcpp::export]] Rcpp::CharacterVector CPL_ogrinfo(Rcpp::CharacterVector obj, Rcpp::CharacterVector options, - Rcpp::CharacterVector oo, Rcpp::CharacterVector co) { + Rcpp::CharacterVector oo, Rcpp::CharacterVector co, bool read_only = false) { set_config_options(co); std::vector options_char = create_options(options, true); std::vector oo_char = create_options(oo, true); // open options GDALDatasetH ds = NULL; #if GDAL_VERSION_NUM >= 3070000 if (obj.size()) - ds = GDALOpenEx((const char *) obj[0], GA_Update, NULL, oo_char.data(), NULL); + ds = GDALOpenEx((const char *) obj[0], read_only ? GA_ReadOnly : GA_Update, NULL, oo_char.data(), NULL); GDALVectorInfoOptions* opt = GDALVectorInfoOptionsNew(options_char.data(), NULL); char *ret_val = GDALVectorInfo(ds, opt); if (ret_val == NULL) From 4b5fab5d5095f8568917ed214ec652e3b067c69e Mon Sep 17 00:00:00 2001 From: edzer Date: Wed, 23 Oct 2024 13:50:57 +0200 Subject: [PATCH 17/43] clarify; #2420, #2460 --- NEWS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c3246e1e7..1f1a5e846 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,10 @@ # version 1.0-19 +* `gdal_utils()` `ogrinfo` has an argument `read_only` which, when `TRUE` (or `options` includes `"-ro"`), opens a datasource in read-only mode (#2460; `sf` did this before 1.0-17); by default a datasource is opened in update (read-write) mode (since sf 1.0-17; #2420) + # version 1.0-18 -* support `POLYGON FULL` simple feature geometry, representing the the entire Earth surface, as used by `s2geometry`; #2441 +* support `POLYGON FULL` simple feature geometry, representing the entire Earth surface, as used by `s2geometry`; #2441 * `st_sfc()` has an argument `oriented` which, when set to `TRUE`, adds an attribute `oriented=TRUE` to an `sfc` object, indicating that this object should not be reoriented in conversion to `s2_geography` (avoiding using the global option `s2_oriented`); `st_as_sfc.bbox()` sets this to `TRUE`; #2441 From 910bcf37fe0d0dc8d0265a0ec9fa5ea59f184b00 Mon Sep 17 00:00:00 2001 From: Andrea Gilardi Date: Thu, 24 Oct 2024 18:36:09 +0200 Subject: [PATCH 18/43] Update NEWS.md Mention the blog post in the NEWS file to improve its discoverability --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 1f1a5e846..208e0d5a5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,7 @@ # version 1.0-18 -* support `POLYGON FULL` simple feature geometry, representing the entire Earth surface, as used by `s2geometry`; #2441 +* support `POLYGON FULL` simple feature geometry, representing the entire Earth surface, as used by `s2geometry`; see also https://r-spatial.org/r/2024/10/11/polygonfull.html for a longer introduction; #2441 * `st_sfc()` has an argument `oriented` which, when set to `TRUE`, adds an attribute `oriented=TRUE` to an `sfc` object, indicating that this object should not be reoriented in conversion to `s2_geography` (avoiding using the global option `s2_oriented`); `st_as_sfc.bbox()` sets this to `TRUE`; #2441 From 90980f72150b2e211c60227ee6e749c17c58266a Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 29 Oct 2024 12:40:24 +0100 Subject: [PATCH 19/43] closes #2463 --- NEWS.md | 2 ++ src/sfc-sfg.cpp | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1f1a5e846..2b03ba660 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # version 1.0-19 +* improve test on empty geometries, which changed in 1.0-18; #2463 + * `gdal_utils()` `ogrinfo` has an argument `read_only` which, when `TRUE` (or `options` includes `"-ro"`), opens a datasource in read-only mode (#2460; `sf` did this before 1.0-17); by default a datasource is opened in update (read-write) mode (since sf 1.0-17; #2420) # version 1.0-18 diff --git a/src/sfc-sfg.cpp b/src/sfc-sfg.cpp index ff25eb5c6..5619aa469 100644 --- a/src/sfc-sfg.cpp +++ b/src/sfc-sfg.cpp @@ -99,10 +99,9 @@ LogicalVector sfc_is_empty(List sfc) { for (R_xlen_t i = 0; i < sfc.size(); i++) { item = sfc[i]; int item_len = Rf_length(item); + bool is_empty = true; if (Rf_inherits(item, "POINT")) { - bool is_empty = true; - if (TYPEOF(item) == REALSXP) { for (int j = 0; j < item_len; j++) { double val = REAL(item)[j]; @@ -120,11 +119,9 @@ LogicalVector sfc_is_empty(List sfc) { } } } - - out[i] = is_empty; - } else { - out[i] = item_len == 0; - } + } else + is_empty = (item_len == 0) || (TYPEOF(item) == VECSXP && Rf_length(VECTOR_ELT(item, 0)) == 0); // #2463 + out[i] = is_empty; } return out; From 13a42be1914e2cca4c460c3cadf528d8cd9abca0 Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 29 Oct 2024 13:57:35 +0100 Subject: [PATCH 20/43] MultiPolygon; closes #2463 --- src/sfc-sfg.cpp | 12 ++++++++++-- tests/sfc.R | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/sfc-sfg.cpp b/src/sfc-sfg.cpp index 5619aa469..ef0fb5619 100644 --- a/src/sfc-sfg.cpp +++ b/src/sfc-sfg.cpp @@ -119,8 +119,16 @@ LogicalVector sfc_is_empty(List sfc) { } } } - } else - is_empty = (item_len == 0) || (TYPEOF(item) == VECSXP && Rf_length(VECTOR_ELT(item, 0)) == 0); // #2463 + } else { + if (item_len == 0) + is_empty = true; + else if (TYPEOF(item) == VECSXP) { // #2463 + item = VECTOR_ELT(item, 0); + is_empty = Rf_length(item) == 0 || // e.g. POLYGON with 1 ring without coordinates + (TYPEOF(item) == VECSXP && Rf_length(VECTOR_ELT(item, 0)) == 0); // same for one level deeper, e.g. MULTIPOLYGON: + } else + is_empty = false; + } out[i] = is_empty; } diff --git a/tests/sfc.R b/tests/sfc.R index 855160f8f..7c56baa5e 100644 --- a/tests/sfc.R +++ b/tests/sfc.R @@ -360,3 +360,8 @@ st_exterior_ring(st_sf(a = 1, geom = spl1)) st_exterior_ring(smpl1[[1]]) st_exterior_ring(st_sfc(smpl1)) st_exterior_ring(st_sf(a = 1, geom = st_sfc(smpl1))) + +'{"type":"Polygon","coordinates":[[]]}' |> read_sf() |> st_is_empty() +# '{"type":"Polygon","coordinates":[]}' |> read_sf() |> st_is_empty() # breaks on GDAL < 3.9 or so +'{"type":"MultiPolygon","coordinates":[[[]]]}' |> read_sf() |> st_is_empty() +'{"type":"MultiPolygon","coordinates":[[]]}' |> read_sf() |> st_is_empty() From a621f1df32a329cb83ef4e78492c748bb87bcfba Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:05:45 +0100 Subject: [PATCH 21/43] enhance `st_as_text()` docs --- R/wkt.R | 5 +++++ man/st_as_text.Rd | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/R/wkt.R b/R/wkt.R index 4c3c58941..14407a2b0 100644 --- a/R/wkt.R +++ b/R/wkt.R @@ -85,6 +85,11 @@ prnt.GEOMETRYCOLLECTION = function(x, ..., EWKT = TRUE) { #' \href{https://www.ogc.org/standard/sfa/}{simple features access} specification and extensions #' (known as EWKT, supported by PostGIS and other simple features implementations for addition of #' a SRID to a WKT string). +#' @note To improve conversion performance, the lwgeom package can be used (it must be installed +#' beforehand) and set the \code{Sys.setenv("LWGEOM_WKT" = "true")} environment variable. This +#' will also result in faster printing of complex geometries. Note that the representation as WKT is +#' different from the sf package and may cause reproducibility problems. An alternative solution is +#' to use the [lwgeom::st_astext()] or [wk::as_wkt()] functions. #' #' @export st_as_text = function(x, ...) UseMethod("st_as_text") diff --git a/man/st_as_text.Rd b/man/st_as_text.Rd index 638ff263b..a87a9e2f1 100644 --- a/man/st_as_text.Rd +++ b/man/st_as_text.Rd @@ -35,6 +35,13 @@ The returned WKT representation of simple feature geometry conforms to the (known as EWKT, supported by PostGIS and other simple features implementations for addition of a SRID to a WKT string). } +\note{ +To improve conversion performance, the lwgeom package can be used (it must be installed +beforehand) and set the \code{Sys.setenv("LWGEOM_WKT" = "true")} environment variable. This +will also result in faster printing of complex geometries. Note that the representation as WKT is +different from the sf package and may cause reproducibility problems. An alternative solution is +to use the \code{\link[lwgeom:st_astext]{lwgeom::st_astext()}} or \code{\link[wk:wkt]{wk::as_wkt()}} functions. +} \examples{ st_as_text(st_point(1:2)) st_as_text(st_sfc(st_point(c(-90,40)), crs = 4326), EWKT = TRUE) From fc8d909440b3918baf4bd89b7f22c1e91131109c Mon Sep 17 00:00:00 2001 From: Andrea Gilardi Date: Thu, 31 Oct 2024 10:26:35 +0000 Subject: [PATCH 22/43] as.ppp.sf accepts ncol(X) > 1 --- NEWS.md | 2 ++ R/spatstat.R | 9 ++++----- tests/spatstat.R | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1f1a5e846..e5cd8fdf8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ * `gdal_utils()` `ogrinfo` has an argument `read_only` which, when `TRUE` (or `options` includes `"-ro"`), opens a datasource in read-only mode (#2460; `sf` did this before 1.0-17); by default a datasource is opened in update (read-write) mode (since sf 1.0-17; #2420) +* the `sf` -> `ppp` conversion accepts a data.frame of marks instead of just 1 column #2450, by @agila5 + # version 1.0-18 * support `POLYGON FULL` simple feature geometry, representing the entire Earth surface, as used by `s2geometry`; #2441 diff --git a/R/spatstat.R b/R/spatstat.R index 8b8127d0e..ef8668bae 100644 --- a/R/spatstat.R +++ b/R/spatstat.R @@ -144,13 +144,12 @@ as.ppp.sf = function(X, ...) { if (st_dimension(X[1,]) == 2) X = X[-1,] st_geometry(X) = NULL # remove geometry column - if (ncol(X) > 1) - warning("only first attribute column is used for marks") - if (ncol(X) == 0) + if (ncol(X) == 0) { pp - else - spatstat.geom::setmarks(pp, X[1]) + } else { + spatstat.geom::setmarks(pp, X) + } } as.owin.POLYGON = function(W, ..., fatal, check_polygons = TRUE) { diff --git a/tests/spatstat.R b/tests/spatstat.R index a2f61f954..454f4a0aa 100644 --- a/tests/spatstat.R +++ b/tests/spatstat.R @@ -108,5 +108,28 @@ as.psp(sf, marks = 5:1) (x = st_as_sf(as.psp(sf))) (y = st_as_sfc(as.psp(sf))) all.equal(st_geometry(x), y) + +# Test sf -> ppp conversion when the conversion involves more than 1 column of mark(s) +# (https://github.com/r-spatial/sf/issues/2450) +reference_ppp <- ppp( + x = c(0.25, 0.75), + y = c(0.25, 0.75), + # We consider a data.frame of marks which includes several types of columns + # (and also a list column) + marks = data.frame( + a = TRUE, b = 1L, c = pi, d = I(list(list(1, 2), list("A", "B", "C"))), + #NB: row.names should always defined as a vector with character character + #since they are converted as characters when applying st_as_sf (see line + #below) which mixes NA and not-NA row.names + row.names = c("point1", "point2") + ) +) +# The st_as_sf conversion returns an sf object where the first row is the Window +# and the other rows are the points +tmp <- st_as_sf(reference_ppp) +pts <- tmp[tmp$label == "point", 1:4] +target_ppp <- as.ppp(pts) +Window(target_ppp) <- owin() +all.equal(reference_ppp, target_ppp) } ## IGNORE_RDIFF_END From 88f4f555d069920c2ee587ac0d2d2c68659ea189 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 1 Nov 2024 19:48:19 +0100 Subject: [PATCH 23/43] CPL_area(): use proper casts to OGRGeometry subtypes, in particular to fix issues with GeometryCollection of Polygon Fixes #2466 --- src/gdal_geom.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gdal_geom.cpp b/src/gdal_geom.cpp index db1781bd2..2a8132086 100644 --- a/src/gdal_geom.cpp +++ b/src/gdal_geom.cpp @@ -12,13 +12,16 @@ Rcpp::NumericVector CPL_area(Rcpp::List sfc) { for (size_t i = 0; i < g.size(); i++) { if (g[i]->getDimension() == 2) { OGRwkbGeometryType gt = OGR_GT_Flatten(g[i]->getGeometryType()); - if (gt == wkbMultiSurface || gt == wkbMultiPolygon) { + if (OGR_GT_IsSubClassOf(gt, wkbGeometryCollection)) { + // will match OGRMultiPolygon, OGRMultiSurface and OGRGeometryCollection OGRGeometryCollection *gc = (OGRGeometryCollection *) g[i]; out[i] = gc->get_Area(); - } else { + } else if (OGR_GT_IsSurface(gt)) { OGRSurface *surf = (OGRSurface *) g[i]; out[i] = surf->get_Area(); - } + } else { + out[i] = 0.0; // not supposed to happen, but who knows... + } } else out[i] = 0.0; OGRGeometryFactory::destroyGeometry(g[i]); From fdfbf98821d850854c093b38cd14f266c6b68b91 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 1 Nov 2024 19:55:27 +0100 Subject: [PATCH 24/43] CPL_length(): fix unchecked cast to OGRGeometryCollection The current implementation would likely crash on things like OGRPolyhedralSurface. --- src/gdal_geom.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gdal_geom.cpp b/src/gdal_geom.cpp index db1781bd2..67fdd4c7b 100644 --- a/src/gdal_geom.cpp +++ b/src/gdal_geom.cpp @@ -63,8 +63,12 @@ Rcpp::NumericVector CPL_length(Rcpp::List sfc) { } break; default: { - OGRGeometryCollection *a = (OGRGeometryCollection *) g[i]; - out[i] = a->get_Length(); + if (OGR_GT_IsSubClassOf(gt, wkbGeometryCollection)) { + OGRGeometryCollection *a = (OGRGeometryCollection *) g[i]; + out[i] = a->get_Length(); + } else { + out[i] = 0.0; + } } } OGRGeometryFactory f; From 538f66bdd47c6a47cc70234083c5daaf44ad13c3 Mon Sep 17 00:00:00 2001 From: edzer Date: Sun, 3 Nov 2024 20:17:49 +0100 Subject: [PATCH 25/43] add news --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 2b03ba660..686c1d6d7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # version 1.0-19 +* fix type checks in C++ GDAL area and length computation functions, anticipating GDAL 3.10.0; #2466, #2468mm, #2469 by @rsbivand and @rouault + * improve test on empty geometries, which changed in 1.0-18; #2463 * `gdal_utils()` `ogrinfo` has an argument `read_only` which, when `TRUE` (or `options` includes `"-ro"`), opens a datasource in read-only mode (#2460; `sf` did this before 1.0-17); by default a datasource is opened in update (read-write) mode (since sf 1.0-17; #2420) From a6f7b1293ebabc78f6c072cab704f8b3585e4953 Mon Sep 17 00:00:00 2001 From: edzer Date: Sun, 3 Nov 2024 20:45:50 +0100 Subject: [PATCH 26/43] add news --- NEWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a56fddab3..4b9106769 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,12 @@ # version 1.0-19 -* fix type checks in C++ GDAL area and length computation functions, anticipating GDAL 3.10.0; #2466, #2468mm, #2469 by @rsbivand and @rouault +* fix type checks in C++ GDAL area and length computation functions, anticipating GDAL 3.10.0; #2466, #2468, #2469 by @rsbivand and @rouault * improve test on empty geometries, which changed in 1.0-18; #2463 * `gdal_utils()` `ogrinfo` has an argument `read_only` which, when `TRUE` (or `options` includes `"-ro"`), opens a datasource in read-only mode (#2460; `sf` did this before 1.0-17); by default a datasource is opened in update (read-write) mode (since sf 1.0-17; #2420) -* the `sf` -> `ppp` conversion accepts a data.frame of marks instead of just 1 column #2450, by @agila5 +* the `sf` -> `ppp` conversion `as.ppp.sf()` accepts a data.frame of marks instead of just 1 column #2450, by @agila5 # version 1.0-18 From dc990d266f69da28ef1385d2d82d342189ee70f6 Mon Sep 17 00:00:00 2001 From: edzer Date: Sun, 3 Nov 2024 20:45:58 +0100 Subject: [PATCH 27/43] clean up st_is_full(); closes #2467 --- R/bbox.R | 2 +- R/init.R | 1 + R/sfc.R | 9 ++------- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/R/bbox.R b/R/bbox.R index 69e265ea6..5679f9252 100644 --- a/R/bbox.R +++ b/R/bbox.R @@ -71,7 +71,7 @@ st_bbox.MULTIPOINT = bbox.Mtrx st_bbox.LINESTRING = bbox.Mtrx #' @export #' @name st_bbox -st_bbox.POLYGON = function(obj, ...) if (sf_use_s2() && length(obj) == 1 && nrow(obj[[1]]) == 2) FULL_bbox_ else bbox.MtrxSet(obj) +st_bbox.POLYGON = function(obj, ...) if (st_is_full(obj)) FULL_bbox_ else bbox.MtrxSet(obj) #' @export #' @name st_bbox st_bbox.MULTILINESTRING = bbox.MtrxSet diff --git a/R/init.R b/R/init.R index 4488157ec..48d500a6e 100644 --- a/R/init.R +++ b/R/init.R @@ -40,6 +40,7 @@ pathGrob <- NULL load_gdal() if ((s2 <- Sys.getenv("_SF_USE_S2")) != "") options(sf_use_s2 = s2 != "false") + FULL_bbox_ <<- st_set_crs(FULL_bbox_, "OGC:CRS84") } .onUnload = function(libname, pkgname) { diff --git a/R/sfc.R b/R/sfc.R index c3230fb2a..6a422abef 100644 --- a/R/sfc.R +++ b/R/sfc.R @@ -641,14 +641,9 @@ st_is_full.sfg = function(x, ..., is_longlat = NULL) { #' @export #' @name st_is_full st_is_full.sfc = function(x, ...) { - if (sf_use_s2() && inherits(x, c("sfc_POLYGON", "sfc_GEOMETRY"))) { - is_longlat = if (!is.null(attr(x, "crs"))) - st_is_longlat(x) - else - NA - #sapply(x, st_is_full.sfg, ..., is_longlat = is_longlat) + if (sf_use_s2() && inherits(x, c("sfc_POLYGON", "sfc_GEOMETRY"))) sfc_is_full(x) - } else + else rep_len(FALSE, length(x)) } From 7bd4e089d018019ca2438ad7493db57fd7114d5f Mon Sep 17 00:00:00 2001 From: edzer Date: Sun, 3 Nov 2024 20:47:25 +0100 Subject: [PATCH 28/43] clean test output --- tests/sfc.Rout.save | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/sfc.Rout.save b/tests/sfc.Rout.save index 4f9ed3003..638a4526e 100644 --- a/tests/sfc.Rout.save +++ b/tests/sfc.Rout.save @@ -1134,6 +1134,14 @@ Geodetic CRS: WGS 84 a geom 1 1 MULTIPOLYGON (((0 0, 10 0, ... > +> '{"type":"Polygon","coordinates":[[]]}' |> read_sf() |> st_is_empty() +[1] TRUE +> # '{"type":"Polygon","coordinates":[]}' |> read_sf() |> st_is_empty() # breaks on GDAL < 3.9 or so +> '{"type":"MultiPolygon","coordinates":[[[]]]}' |> read_sf() |> st_is_empty() +[1] TRUE +> '{"type":"MultiPolygon","coordinates":[[]]}' |> read_sf() |> st_is_empty() +[1] TRUE +> > proc.time() user system elapsed - 5.266 1.417 5.341 + 4.932 1.534 5.006 From ee68c8841040f3ecfb5e2394208da4b0e2afebae Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:52:22 +0100 Subject: [PATCH 29/43] fix typo in vignette 7 --- vignettes/sf7.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vignettes/sf7.Rmd b/vignettes/sf7.Rmd index d074b4d30..09ce83ec6 100644 --- a/vignettes/sf7.Rmd +++ b/vignettes/sf7.Rmd @@ -101,7 +101,7 @@ and transformations _on the sphere_. This means: The `s2` package is really a wrapper around the C++ [s2geometry](http://s2geometry.io) library which was written by Google, and which is used in many of its products (e.g. Google -Maps, Google Earth Engine, Bigquery GIS) and has been translated +Maps, Google Earth Engine, BigQuery GIS) and has been translated in several other programming languages. With projected coordinates `sf` continues to work in $R^2$ as before. @@ -211,7 +211,7 @@ st_intersects(a, b) # default: closed Computing the minimum and maximum values over coordinate ranges, as `sf` does with `st_bbox()`, is of limited value for spherical -coordinates because due the the spherical space, the _area covered_ +coordinates because due the spherical space, the _area covered_ is not necessarily covered by the coordinate range. Two examples: * small regions covering the antimeridian (longitude +/- 180) end up with a huge longitude range, which doesn't make _clear_ the antimeridian is spanned @@ -340,7 +340,7 @@ excessive simplification (bottom right). Note that buffers created with s2 _alwa follow s2 cell boundaries, they are never smooth. Hence, choosing a large number for `max_cells` leads to seemingly smooth but, zoomed in, very complex buffers. -To achieve a similar result you could first transform the result and then use `sf::st_buffer()`. A simple benchmark shows the +To achieve a similar result, you could first transform the result and then use `sf::st_buffer()`. A simple benchmark shows the computational efficiency of the `s2` geometry engine in comparison with transforming and then creating buffers: @@ -384,7 +384,7 @@ deciding on workflows and selecting appropriate levels of level of geographic re be an iterative process. `st_buffer()` as powered by GEOS, for $R^2$ data, are smooth and (nearly) exact. `st_buffer()` as powered by $S^2$ is rougher, complex, non-smooth, and may need tuning. -An common pattern where `st_buffer()` is used is this: +A common pattern where `st_buffer()` is used is this: * compute buffers around a set of features `x` (points, lines, polygons) * within each of these buffers, find all occurrences of some other spatial From 01bbf3c3748169001167b2d8f528415266f2e02f Mon Sep 17 00:00:00 2001 From: edzer Date: Fri, 22 Nov 2024 22:58:02 +0100 Subject: [PATCH 30/43] fix #2481 --- R/geom-measures.R | 2 +- man/geos_measures.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/geom-measures.R b/R/geom-measures.R index 4c85df450..c19dd7c16 100644 --- a/R/geom-measures.R +++ b/R/geom-measures.R @@ -23,7 +23,7 @@ st_dimension = function(x, NA_if_empty = TRUE) #' @export #' @return If the coordinate reference system of \code{x} was set, these functions return values with unit of measurement; see \link[units]{set_units}. #' -#' st_area returns the area of a geometry, in the coordinate reference system used; in case \code{x} is in degrees longitude/latitude, \link[lwgeom:geod]{st_geod_area} is used for area calculation. +#' st_area returns the area of each feature geometry, computed in the coordinate reference system used. In case \code{x} has geodetic coordinates (unprojected), then if `sf_use_s2()` is `FALSE` \link[lwgeom:geod]{st_geod_area} is used for area calculation, if it is `TRUE` then \link[s2:s2_is_collection]{s2_area} is used: the former assumes an ellipsoidal shape, the latter a spherical shape of the Earth. In case of projected data, areas are computed in flat space. The argument `...` can be used to specify `radius` to \link[s2:s2_is_collection]{s2_area}, to modify the Earth radius. #' @examples #' b0 = st_polygon(list(rbind(c(-1,-1), c(1,-1), c(1,1), c(-1,1), c(-1,-1)))) #' b1 = b0 + 2 diff --git a/man/geos_measures.Rd b/man/geos_measures.Rd index 4f0b88c19..b13aee6eb 100644 --- a/man/geos_measures.Rd +++ b/man/geos_measures.Rd @@ -48,7 +48,7 @@ st_distance( \value{ If the coordinate reference system of \code{x} was set, these functions return values with unit of measurement; see \link[units]{set_units}. -st_area returns the area of a geometry, in the coordinate reference system used; in case \code{x} is in degrees longitude/latitude, \link[lwgeom:geod]{st_geod_area} is used for area calculation. +st_area returns the area of each feature geometry, computed in the coordinate reference system used. In case \code{x} has geodetic coordinates (unprojected), then if \code{sf_use_s2()} is \code{FALSE} \link[lwgeom:geod]{st_geod_area} is used for area calculation, if it is \code{TRUE} then \link[s2:s2_is_collection]{s2_area} is used: the former assumes an ellipsoidal shape, the latter a spherical shape of the Earth. In case of projected data, areas are computed in flat space. The argument \code{...} can be used to specify \code{radius} to \link[s2:s2_is_collection]{s2_area}, to modify the Earth radius. st_length returns the length of a \code{LINESTRING} or \code{MULTILINESTRING} geometry, using the coordinate reference system. \code{POINT}, \code{MULTIPOINT}, \code{POLYGON} or \code{MULTIPOLYGON} geometries return zero. From c00a18803106913e36e8cdde44e171559a3caaf5 Mon Sep 17 00:00:00 2001 From: edzer Date: Fri, 22 Nov 2024 22:58:38 +0100 Subject: [PATCH 31/43] links --- .Rbuildignore | 1 + R/wkt.R | 4 ++-- man/geos_unary.Rd | 12 +++++++++--- man/st_as_sfc.Rd | 2 +- man/st_as_text.Rd | 2 +- vignettes/sf1.Rmd | 4 ++-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 336ab726e..d18654298 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -28,3 +28,4 @@ changes1.txt changes2.txt changes3.txt changes.txt +aware.patch diff --git a/R/wkt.R b/R/wkt.R index 14407a2b0..70dfa080b 100644 --- a/R/wkt.R +++ b/R/wkt.R @@ -82,7 +82,7 @@ prnt.GEOMETRYCOLLECTION = function(x, ..., EWKT = TRUE) { #' @param ... modifiers; in particular \code{digits} can be passed to control the number of digits used #' @name st_as_text #' @details The returned WKT representation of simple feature geometry conforms to the -#' \href{https://www.ogc.org/standard/sfa/}{simple features access} specification and extensions +#' \href{https://www.ogc.org/publications/standard/sfa/}{simple features access} specification and extensions #' (known as EWKT, supported by PostGIS and other simple features implementations for addition of #' a SRID to a WKT string). #' @note To improve conversion performance, the lwgeom package can be used (it must be installed @@ -144,7 +144,7 @@ st_as_text.sfc = function(x, ..., EWKT = FALSE) { #' @rdname st_as_sfc #' @md #' @details If `x` is a character vector, it should be a vector containing -#' [well-known-text](https://www.ogc.org/standard/wkt-crs/), or +#' [well-known-text](https://www.ogc.org/publications/standard/wkt-crs/), or #' Postgis EWKT or GeoJSON representations of a single geometry for each vector element. #' @param crs integer or character; coordinate reference system for the #' @param GeoJSON logical; if \code{TRUE}, try to read geometries from GeoJSON text strings diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index ee90936d0..5505e0ffe 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -49,7 +49,13 @@ st_inscribed_circle(x, dTolerance, ...) st_minimum_rotated_rectangle(x, ...) -st_voronoi(x, envelope, dTolerance = 0, bOnlyEdges = FALSE, point_order = FALSE) +st_voronoi( + x, + envelope, + dTolerance = 0, + bOnlyEdges = FALSE, + point_order = FALSE +) st_polygonize(x) @@ -115,13 +121,13 @@ meters.} \item{envelope}{object of class \code{sfc} or \code{sfg} containing a \code{POLYGON} with the envelope for a voronoi diagram; this only takes effect when it is larger than the default envelope, chosen when \code{envelope} is an empty polygon} +\item{point_order}{logical; preserve point order if TRUE and GEOS version >= 3.12; overrides bOnlyEdges} + \item{directed}{logical; if \code{TRUE}, lines with opposite directions will not be merged} \item{of_largest_polygon}{logical; for \code{st_centroid}: if \code{TRUE}, return centroid of the largest (sub)polygon of a \code{MULTIPOLYGON} rather than of the whole \code{MULTIPOLYGON}} \item{dfMaxLength}{maximum length of a line segment. If \code{x} has geographical coordinates (long/lat), \code{dfMaxLength} is either a numeric expressed in meter, or an object of class \code{units} with length units \code{rad} or \code{degree}; segmentation in the long/lat case takes place along the great circle, using \link[lwgeom:geod]{st_geod_segmentize}.} - -\item{point_order}{logical; preserve point order if TRUE and GEOS version >= 3.12; overrides bOnlyEdges} } \value{ an object of the same class of \code{x}, with manipulated geometry. diff --git a/man/st_as_sfc.Rd b/man/st_as_sfc.Rd index 6b71a53b3..95d5304b0 100644 --- a/man/st_as_sfc.Rd +++ b/man/st_as_sfc.Rd @@ -100,7 +100,7 @@ Convert foreign geometry object to an sfc object When converting from WKB, the object \code{x} is either a character vector such as typically obtained from PostGIS (either with leading "0x" or without), or a list with raw vectors representing the features in binary (raw) form. If \code{x} is a character vector, it should be a vector containing -\href{https://www.ogc.org/standard/wkt-crs/}{well-known-text}, or +\href{https://www.ogc.org/publications/standard/wkt-crs/}{well-known-text}, or Postgis EWKT or GeoJSON representations of a single geometry for each vector element. If \code{x} is a \code{factor}, it is converted to \code{character}. diff --git a/man/st_as_text.Rd b/man/st_as_text.Rd index a87a9e2f1..43c3fc2a5 100644 --- a/man/st_as_text.Rd +++ b/man/st_as_text.Rd @@ -31,7 +31,7 @@ Return Well-known Text representation of simple feature geometry or coordinate r } \details{ The returned WKT representation of simple feature geometry conforms to the -\href{https://www.ogc.org/standard/sfa/}{simple features access} specification and extensions +\href{https://www.ogc.org/publications/standard/sfa/}{simple features access} specification and extensions (known as EWKT, supported by PostGIS and other simple features implementations for addition of a SRID to a WKT string). } diff --git a/vignettes/sf1.Rmd b/vignettes/sf1.Rmd index fb1c36ebf..b622784ec 100644 --- a/vignettes/sf1.Rmd +++ b/vignettes/sf1.Rmd @@ -20,7 +20,7 @@ if (file.exists("nc.shp")) file.remove("nc.shp", "nc.dbf", "nc.shx") ``` -[Simple features](https://en.wikipedia.org/wiki/Simple_Features) or [_simple feature access_](https://www.ogc.org/standard/sfa/) refers to a formal standard (ISO 19125-1:2004) that describes how objects in the real world can be represented in computers, with emphasis on the _spatial_ geometry of these objects. It also describes how such objects can be stored in and retrieved from databases, and which geometrical operations should be defined for them. +[Simple features](https://en.wikipedia.org/wiki/Simple_Features) or [_simple feature access_](https://www.ogc.org/publications/standard/sfa/) refers to a formal standard (ISO 19125-1:2004) that describes how objects in the real world can be represented in computers, with emphasis on the _spatial_ geometry of these objects. It also describes how such objects can be stored in and retrieved from databases, and which geometrical operations should be defined for them. The standard is widely implemented in spatial databases (such as [PostGIS](https://postgis.net/)), commercial GIS (e.g., [ESRI @@ -72,7 +72,7 @@ features are based on 2D geometry with linear interpolation between vertices._" We will see soon that the same standard will extend its coverage beyond 2D and beyond linear interpolation. Here, we take simple features as the data structures and operations described -in the [standard](https://www.ogc.org/standard/sfa/). +in the [standard](https://www.ogc.org/publications/standard/sfa/). ## Dimensions From 1e8fca367ad585b3229694af4f5d8a14139d989c Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 26 Nov 2024 22:36:03 +0100 Subject: [PATCH 32/43] closes #2473 --- NAMESPACE | 4 ++++ NEWS.md | 4 ++++ R/geom-transformers.R | 28 ++++++++++++++++++++++++++++ man/geos_unary.Rd | 7 +++++++ src/geos.cpp | 8 +++++++- 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 3c2cf0128..b8bb8598d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -270,6 +270,9 @@ S3method(st_m_range,sfc) S3method(st_make_valid,sf) S3method(st_make_valid,sfc) S3method(st_make_valid,sfg) +S3method(st_minimum_bounding_circle,sf) +S3method(st_minimum_bounding_circle,sfc) +S3method(st_minimum_bounding_circle,sfg) S3method(st_minimum_rotated_rectangle,sf) S3method(st_minimum_rotated_rectangle,sfc) S3method(st_minimum_rotated_rectangle,sfg) @@ -485,6 +488,7 @@ export(st_linestring) export(st_m_range) export(st_make_grid) export(st_make_valid) +export(st_minimum_bounding_circle) export(st_minimum_rotated_rectangle) export(st_multilinestring) export(st_multipoint) diff --git a/NEWS.md b/NEWS.md index 2e33dba55..a07eafe7e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# version 1.0-20 + +* `st_minimum_bounding_circle()` returns geometries representing the smallest circle that contains the input; #2473 + # version 1.0-19 * fix type checks in C++ GDAL area and length computation functions, anticipating GDAL 3.10.0; #2466, #2468, #2469 by @rsbivand and @rouault diff --git a/R/geom-transformers.R b/R/geom-transformers.R index 1dd4eba9d..03b50ff34 100644 --- a/R/geom-transformers.R +++ b/R/geom-transformers.R @@ -451,6 +451,34 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) { st_set_geometry(x, st_minimum_rotated_rectangle(st_geometry(x)), ...) } +#' @name geos_unary +#' @details \code{st_minimum_bounding_circle} +#' returns a geometry which represents the "minimum bounding circle", +#' the smallest circle that contains the input. +#' @export +st_minimum_bounding_circle = function(x, ...) + UseMethod("st_minimum_bounding_circle") + +#' @export +st_minimum_bounding_circle.sfg = function(x, ...) { + get_first_sfg(st_minimum_bounding_circle(st_sfc(x), ...)) +} + +#' @export +st_minimum_bounding_circle.sfc = function(x, ...) { + if (compareVersion(CPL_geos_version(), "3.8.0") > -1) { # >= + if (isTRUE(st_is_longlat(x))) + warning("st_minimum_rotated_rectangle does not work correctly for longitude/latitude data") + st_sfc(CPL_geos_op("bounding_circle", x, 0L, integer(0), + dTolerance = 0., logical(0), bOnlyEdges = as.integer(FALSE))) + } else + stop("for st_minimum_bounding_circle, GEOS version 3.8.0 or higher is required") +} + +#' @export +st_minimum_bounding_circle.sf = function(x, ...) { + st_set_geometry(x, st_minimum_bounding_circle(st_geometry(x)), ...) +} #' @name geos_unary #' @export diff --git a/man/geos_unary.Rd b/man/geos_unary.Rd index 5505e0ffe..0e1f4b8d4 100644 --- a/man/geos_unary.Rd +++ b/man/geos_unary.Rd @@ -11,6 +11,7 @@ \alias{st_triangulate_constrained} \alias{st_inscribed_circle} \alias{st_minimum_rotated_rectangle} +\alias{st_minimum_bounding_circle} \alias{st_voronoi} \alias{st_polygonize} \alias{st_line_merge} @@ -49,6 +50,8 @@ st_inscribed_circle(x, dTolerance, ...) st_minimum_rotated_rectangle(x, ...) +st_minimum_bounding_circle(x, ...) + st_voronoi( x, envelope, @@ -169,6 +172,10 @@ rectangle has width equal to the minimum diameter, and a longer length. If the convex hill of the input is degenerate (a line or point) a linestring or point is returned. +\code{st_minimum_bounding_circle} +returns a geometry which represents the "minimum bounding circle", +the smallest circle that contains the input. + \code{st_voronoi} creates voronoi tessellation. \code{st_voronoi} requires GEOS version 3.5 or above \code{st_polygonize} creates a polygon from lines that form a closed ring. In case of \code{st_polygonize}, \code{x} must be an object of class \code{LINESTRING} or \code{MULTILINESTRING}, or an \code{sfc} geometry list-column object containing these diff --git a/src/geos.cpp b/src/geos.cpp index 5846d6952..fc08a9ed3 100644 --- a/src/geos.cpp +++ b/src/geos.cpp @@ -885,6 +885,13 @@ Rcpp::List CPL_geos_op(std::string op, Rcpp::List sfc, } } else #endif +#ifdef HAVE380 + if (op == "bounding_circle") { + double r; + for (size_t i = 0; i < g.size(); i++) + out[i] = geos_ptr(chkNULL(GEOSMinimumBoundingCircle_r(hGEOSCtxt, g[i].get(), &r, NULL)), hGEOSCtxt); + } else +#endif #ifdef HAVE390 if (op == "inscribed_circle") { for (size_t i = 0; i < g.size(); i++) { @@ -906,7 +913,6 @@ Rcpp::List CPL_geos_op(std::string op, Rcpp::List sfc, return ret; } - // [[Rcpp::export]] Rcpp::List CPL_geos_voronoi(Rcpp::List sfc, Rcpp::List env, double dTolerance = 0.0, int bOnlyEdges = 1) { From 39e8f51372e19237d95cd406ae4683a253c3c5b2 Mon Sep 17 00:00:00 2001 From: edzer Date: Fri, 29 Nov 2024 15:59:44 +0100 Subject: [PATCH 33/43] closes #2484 --- NEWS.md | 2 ++ R/tidyverse.R | 9 +++++++-- man/tidyverse.Rd | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index a07eafe7e..a93338295 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # version 1.0-20 +* `distinct.sf()` allows for comparing exact equality of geometries when `exact = TRUE`; #2484 + * `st_minimum_bounding_circle()` returns geometries representing the smallest circle that contains the input; #2473 # version 1.0-19 diff --git a/R/tidyverse.R b/R/tidyverse.R index 7e2ddc83d..8c1c84b41 100644 --- a/R/tidyverse.R +++ b/R/tidyverse.R @@ -345,15 +345,20 @@ summarise.sf <- function(.data, ..., .dots, do_union = TRUE, is_coverage = FALSE #' @name tidyverse #' @param .keep_all see corresponding function in dplyr +#' @param exact logical; if `TRUE` use \link{st_equals_exact} for geometry comparisons +#' @param par numeric; passed on to \link{st_equals_exact} #' @examples #' if (require(dplyr, quietly = TRUE)) { #' nc[c(1:100, 1:10), ] %>% distinct() %>% nrow() #' } #' @details \code{distinct} gives distinct records for which all attributes and geometries are distinct; \link{st_equals} is used to find out which geometries are distinct. -distinct.sf <- function(.data, ..., .keep_all = FALSE) { +distinct.sf <- function(.data, ..., .keep_all = FALSE, exact = FALSE, par = 0.) { sf_column = attr(.data, "sf_column") geom = st_geometry(.data) - eq = sapply(st_equals(.data), head, n = 1) + eq = if (exact) + sapply(st_equals_exact(.data, par = par), head, n = 1) + else + sapply(st_equals(.data), head, n = 1) if (is.list(eq) && length(eq) == 0) # empty list: geometry was empty set eq = integer(0) empties = which(lengths(eq) == 0) diff --git a/man/tidyverse.Rd b/man/tidyverse.Rd index 1ec7b2eb0..5e29aa5ef 100644 --- a/man/tidyverse.Rd +++ b/man/tidyverse.Rd @@ -61,7 +61,7 @@ slice.sf(.data, ..., .dots) summarise.sf(.data, ..., .dots, do_union = TRUE, is_coverage = FALSE) -distinct.sf(.data, ..., .keep_all = FALSE) +distinct.sf(.data, ..., .keep_all = FALSE, exact = FALSE, par = 0) gather.sf( data, @@ -186,6 +186,10 @@ more details.} \item{.keep_all}{see corresponding function in dplyr} +\item{exact}{logical; if \code{TRUE} use \link{st_equals_exact} for geometry comparisons} + +\item{par}{numeric; passed on to \link{st_equals_exact}} + \item{data}{see original function docs} \item{key}{see original function docs} From 4d7ab70ab686e232b6d7c07c66530dccc17be497 Mon Sep 17 00:00:00 2001 From: Roger Bivand Date: Fri, 29 Nov 2024 21:54:51 +0100 Subject: [PATCH 34/43] suggested link to https://r-spatial.github.io/sf/#installing in configure.ac --- configure | 636 ++++++++++++++++++++++++++++----------------------- configure.ac | 43 ++-- 2 files changed, 362 insertions(+), 317 deletions(-) diff --git a/configure b/configure index 23d14bc07..4838888f7 100755 --- a/configure +++ b/configure @@ -1,9 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71. +# Generated by GNU Autoconf 2.72. # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # @@ -15,7 +15,6 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -24,12 +23,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -101,7 +101,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -131,15 +131,14 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: @@ -147,12 +146,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi " @@ -170,8 +170,9 @@ as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else \$as_nop - exitcode=1; echo positional parameters were not saved. +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -184,14 +185,15 @@ test -x / || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else $as_nop - as_have_required=no +else case e in #( + e) as_have_required=no ;; +esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -224,12 +226,13 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi +fi ;; +esac fi @@ -251,7 +254,7 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi @@ -270,7 +273,8 @@ $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 -fi +fi ;; +esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -309,14 +313,6 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -385,11 +381,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -403,21 +400,14 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -491,6 +481,8 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits /[$]LINENO/= ' <$as_myself | sed ' + t clear + :clear s/[$]LINENO.*/&-/ t lineno b @@ -539,7 +531,6 @@ esac as_echo='printf %s\n' as_echo_n='printf %s' - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -551,9 +542,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -578,10 +569,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 /dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -855,7 +848,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1068,7 +1061,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1084,7 +1077,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1114,8 +1107,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" ;; *=*) @@ -1123,7 +1116,7 @@ Try \`$0 --help' for more information" # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1173,7 +1166,7 @@ do as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: `$host' +# There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -1241,7 +1234,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1269,7 +1262,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures this package to adapt to many kinds of systems. +'configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1283,11 +1276,11 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' + -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] + --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -1295,10 +1288,10 @@ Installation directories: --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. +By default, 'make install' will install all the files in +'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify +an installation prefix other than '$ac_default_prefix' using '--prefix', +for instance '--prefix=\$HOME'. For better control, use the options below. @@ -1362,7 +1355,7 @@ Some influential environment variables: CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory -Use these variables to override the choices made by `configure' or to help +Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. @@ -1430,9 +1423,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.71 +generated by GNU Autoconf 2.72 -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1471,11 +1464,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1494,8 +1488,8 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -1503,10 +1497,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1546,11 +1542,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -1586,7 +1583,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -1832,10 +1829,10 @@ esac printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi done @@ -1871,9 +1868,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -1887,6 +1882,21 @@ static char *f (char * (*g) (char **, int), char **p, ...) return s; } +/* C89 style stringification. */ +#define noexpand_stringify(a) #a +const char *stringified = noexpand_stringify(arbitrary+token=sequence); + +/* C89 style token pasting. Exercises some of the corner cases that + e.g. old MSVC gets wrong, but not very hard. */ +#define noexpand_concat(a,b) a##b +#define expand_concat(a,b) noexpand_concat(a,b) +extern int vA; +extern int vbee; +#define aye A +#define bee B +int *pvA = &expand_concat(v,aye); +int *pvbee = &noexpand_concat(v,bee); + /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated @@ -1914,16 +1924,19 @@ ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? +/* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif +// See if C++-style comments work. + #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); +extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare @@ -1973,7 +1986,6 @@ typedef const char *ccp; static inline int test_restrict (ccp restrict text) { - // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) @@ -2039,6 +2051,8 @@ ac_c_conftest_c99_main=' ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; + // Work around memory leak warnings. + free (ia); // Check named initializers. struct named_init ni = { @@ -2060,7 +2074,7 @@ ac_c_conftest_c99_main=' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? +/* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif @@ -2183,12 +2197,12 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -2197,18 +2211,18 @@ printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. @@ -2224,11 +2238,11 @@ printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## @@ -2285,6 +2299,11 @@ printf "%s\n" "$as_me: CXX: ${CXX}" >&6;} # AC_MSG_NOTICE([${PACKAGE_NAME}: ${PACKAGE_VERSION}]) +GENERIC_INSTALL_MESSAGE=" +*** Installing this package from source requires the prior +*** installation of external software, see for details +*** https://r-spatial.github.io/sf/#installing" + #GDAL GDAL_CONFIG="gdal-config" @@ -2313,8 +2332,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_GDAL_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - case $GDAL_CONFIG in +else case e in #( + e) case $GDAL_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_GDAL_CONFIG="$GDAL_CONFIG" # Let the user override the test with a path. ;; @@ -2340,6 +2359,7 @@ IFS=$as_save_IFS test -z "$ac_cv_path_GDAL_CONFIG" && ac_cv_path_GDAL_CONFIG=""no"" ;; +esac ;; esac fi GDAL_CONFIG=$ac_cv_path_GDAL_CONFIG @@ -2355,7 +2375,7 @@ fi if test "$GDAL_CONFIG" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "gdal-config not found or not executable." "$LINENO" 5 + as_fn_error $? "gdal-config not found or not executable. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gdal-config exists" >&5 @@ -2366,7 +2386,7 @@ printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "gdal-config not found - configure argument error." "$LINENO" 5 + as_fn_error $? "gdal-config not found - configure argument error. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gdal-config executable" >&5 printf %s "checking gdal-config executable... " >&6; } @@ -2376,7 +2396,7 @@ printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "gdal-config not executable." "$LINENO" 5 + as_fn_error $? "gdal-config not executable. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi fi @@ -2392,20 +2412,7 @@ then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - echo "Error: gdal-config not found" - echo "The gdal-config script distributed with GDAL could not be found." - echo "If you have not installed the GDAL libraries, you can" - echo "download the source from http://www.gdal.org/" - echo "If you have installed the GDAL libraries, then make sure that" - echo "gdal-config is in your path. Try typing gdal-config at a" - echo "shell prompt and see if it runs. If not, use:" - echo " --configure-args='--with-gdal-config=/usr/local/bin/gdal-config'" - echo "with appropriate values for your installation." - echo "" - - exit 1 + as_fn_error $? "gdal-config not found. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: GDAL: ${GDAL_VERSION}" >&5 @@ -2467,8 +2474,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2490,7 +2497,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -2512,8 +2520,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2535,7 +2543,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -2570,8 +2579,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2593,7 +2602,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -2615,8 +2625,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -2655,7 +2665,8 @@ if test $ac_prog_rejected = yes; then ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -2679,8 +2690,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2702,7 +2713,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -2728,8 +2740,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2751,7 +2763,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -2789,8 +2802,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2812,7 +2825,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -2834,8 +2848,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2857,7 +2871,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -2886,10 +2901,10 @@ fi fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -2961,8 +2976,8 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. +# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -2982,7 +2997,7 @@ do ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' + # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -2993,8 +3008,9 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else $as_nop - ac_file='' +else case e in #( + e) ac_file='' ;; +esac fi if test -z "$ac_file" then : @@ -3003,13 +3019,14 @@ printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } @@ -3033,10 +3050,10 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. + # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) +# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will +# work properly (i.e., refer to 'conftest.exe'), while it won't with +# 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -3046,11 +3063,12 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3066,6 +3084,8 @@ int main (void) { FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; return ferror (f) || fclose (f) != 0; ; @@ -3105,26 +3125,27 @@ printf "%s\n" "$ac_try_echo"; } >&5 if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -3156,16 +3177,18 @@ then : break;; esac done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } @@ -3176,8 +3199,8 @@ printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -3194,12 +3217,14 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -3217,8 +3242,8 @@ printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -3236,8 +3261,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" +else case e in #( + e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3252,8 +3277,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3270,12 +3295,15 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -3302,8 +3330,8 @@ printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no +else case e in #( + e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3320,25 +3348,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" + CC="$CC $ac_cv_prog_cc_c11" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 + ac_prog_cc_stdc=c11 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -3348,8 +3379,8 @@ printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no +else case e in #( + e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3366,25 +3397,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" + CC="$CC $ac_cv_prog_cc_c99" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 + ac_prog_cc_stdc=c99 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -3394,8 +3428,8 @@ printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no +else case e in #( + e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3412,25 +3446,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" + CC="$CC $ac_cv_prog_cc_c89" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 + ac_prog_cc_stdc=c89 ;; +esac fi fi @@ -3477,13 +3514,14 @@ if test "x$ac_cv_header_gdal_h" = xyes then : printf "%s\n" "#define HAVE_GDAL_H 1" >>confdefs.h -else $as_nop - gdalok=no +else case e in #( + e) gdalok=no ;; +esac fi done if test "${gdalok}" = no; then - as_fn_error $? "gdal.h not found in given locations." "$LINENO" 5 + as_fn_error $? "gdal.h not found in given locations. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi NEED_DEPS=no @@ -3536,7 +3574,7 @@ if test "${gdalok}" = no; then cat errors.txt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Install failure: compilation and/or linkage problems." >&5 printf "%s\n" "$as_me: Install failure: compilation and/or linkage problems." >&6;} - as_fn_error $? "GDALAllRegister not found in libgdal." "$LINENO" 5 + as_fn_error $? "GDALAllRegister not found in libgdal. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi rm -f gdal_test errors.txt gdal_test.cpp @@ -3770,8 +3808,9 @@ if test "x$ac_cv_header_proj_h" = xyes then : printf "%s\n" "#define HAVE_PROJ_H 1" >>confdefs.h -else $as_nop - PROJH=no +else case e in #( + e) PROJH=no ;; +esac fi done @@ -3794,8 +3833,9 @@ if test "x$ac_cv_header_proj_api_h" = xyes then : printf "%s\n" "#define HAVE_PROJ_API_H 1" >>confdefs.h -else $as_nop - proj4ok=no +else case e in #( + e) proj4ok=no ;; +esac fi done @@ -3841,16 +3881,22 @@ printf %s "checking for pj_init_plus in -lproj... " >&6; } if test ${ac_cv_lib_proj_pj_init_plus+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lproj $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pj_init_plus (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pj_init_plus (void); int main (void) { @@ -3862,12 +3908,14 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_proj_pj_init_plus=yes -else $as_nop - ac_cv_lib_proj_pj_init_plus=no +else case e in #( + e) ac_cv_lib_proj_pj_init_plus=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_proj_pj_init_plus" >&5 printf "%s\n" "$ac_cv_lib_proj_pj_init_plus" >&6; } @@ -3877,12 +3925,13 @@ then : LIBS="-lproj $LIBS" -else $as_nop - proj4ok=no +else case e in #( + e) proj4ok=no ;; +esac fi if test "${proj4ok}" = no; then - as_fn_error $? "libproj not found in standard or given locations." "$LINENO" 5 + as_fn_error $? "libproj not found in standard or given locations. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi cat > proj_conf_test.c <<_EOCONF #include @@ -3919,7 +3968,7 @@ printf "%s\n" "no" >&6; } printf "%s\n" "yes" >&6; } fi if test "${proj6ok}" = no; then - as_fn_error $? "libproj or sqlite3 not found in standard or given locations." "$LINENO" 5 + as_fn_error $? "libproj or sqlite3 not found in standard or given locations. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi cat > proj_conf_test.c <<_EOCONF @@ -4153,8 +4202,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_GEOS_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - case $GEOS_CONFIG in +else case e in #( + e) case $GEOS_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_GEOS_CONFIG="$GEOS_CONFIG" # Let the user override the test with a path. ;; @@ -4180,6 +4229,7 @@ IFS=$as_save_IFS test -z "$ac_cv_path_GEOS_CONFIG" && ac_cv_path_GEOS_CONFIG=""no"" ;; +esac ;; esac fi GEOS_CONFIG=$ac_cv_path_GEOS_CONFIG @@ -4195,7 +4245,7 @@ fi if test "$GEOS_CONFIG" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "geos-config not found or not executable." "$LINENO" 5 + as_fn_error $? "geos-config not found or not executable. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking geos-config exists" >&5 @@ -4206,7 +4256,7 @@ printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "geos-config not found - configure argument error." "$LINENO" 5 + as_fn_error $? "geos-config not found - configure argument error. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking geos-config executable" >&5 printf %s "checking geos-config executable... " >&6; } @@ -4216,7 +4266,7 @@ printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "geos-config not executable." "$LINENO" 5 + as_fn_error $? "geos-config not executable. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi fi @@ -4275,13 +4325,14 @@ if test "x$ac_cv_header_geos_c_h" = xyes then : printf "%s\n" "#define HAVE_GEOS_C_H 1" >>confdefs.h -else $as_nop - geosok=no +else case e in #( + e) geosok=no ;; +esac fi done if test "${geosok}" = no; then - as_fn_error $? "geos_c.h not found in given locations." "$LINENO" 5 + as_fn_error $? "geos_c.h not found in given locations. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 fi cat > geos_test.cpp <<_EOCONF @@ -4330,7 +4381,7 @@ printf "%s\n" "no" >&6; } cat errors.txt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Install failure: compilation and/or linkage problems." >&5 printf "%s\n" "$as_me: Install failure: compilation and/or linkage problems." >&6;} - as_fn_error $? "initGEOS_r not found in libgeos_c." "$LINENO" 5 + as_fn_error $? "initGEOS_r not found in libgeos_c. ${GENERIC_INSTALL_MESSAGE}" "$LINENO" 5 else PKG_LIBS="${PKG_LIBS} ${GEOS_DEP_CLIBS}" @@ -4367,8 +4418,8 @@ cat >confcache <<\_ACEOF # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the +# 'ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF @@ -4398,14 +4449,14 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote + # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) - # `set' quotes correctly as required by POSIX, so do not add quotes. + # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | @@ -4469,9 +4520,7 @@ s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g +s/[][ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\$/$$/g H :any @@ -4531,7 +4580,6 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -4540,12 +4588,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -4617,7 +4666,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -4646,7 +4695,6 @@ as_fn_error () } # as_fn_error - # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -4686,11 +4734,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -4704,11 +4753,12 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith @@ -4791,9 +4841,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -4874,10 +4924,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 @@ -4893,7 +4945,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -4920,7 +4972,7 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions +'$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -4948,10 +5000,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.71, +configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -5008,8 +5060,8 @@ do ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -5059,7 +5111,7 @@ do case $ac_config_target in "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done @@ -5077,7 +5129,7 @@ fi # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. +# after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= @@ -5101,7 +5153,7 @@ ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. +# This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then @@ -5267,7 +5319,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -5289,19 +5341,19 @@ do -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. + # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is `configure' which instantiates (i.e., don't + # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` @@ -5425,7 +5477,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 esac _ACEOF -# Neutralize VPATH when `$srcdir' = `.'. +# Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -5454,9 +5506,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" diff --git a/configure.ac b/configure.ac index a21b76edd..77a55224b 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,11 @@ AC_MSG_NOTICE([CXX: ${CXX}]) # AC_MSG_NOTICE([${PACKAGE_NAME}: ${PACKAGE_VERSION}]) +GENERIC_INSTALL_MESSAGE=" +*** Installing this package from source requires the prior +*** installation of external software, see for details +*** https://r-spatial.github.io/sf/#installing" + #GDAL GDAL_CONFIG="gdal-config" @@ -60,7 +65,7 @@ if test ["$GDAL_CONFIG_SET" = "no"] ; then AC_PATH_PROG([GDAL_CONFIG], ["$GDAL_CONFIG"],["no"]) if test ["$GDAL_CONFIG" = "no"] ; then AC_MSG_RESULT(no) - AC_MSG_ERROR([gdal-config not found or not executable.]) + AC_MSG_ERROR([gdal-config not found or not executable. ${GENERIC_INSTALL_MESSAGE}]) fi else AC_MSG_CHECKING(gdal-config exists) @@ -68,14 +73,14 @@ else AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) - AC_MSG_ERROR([gdal-config not found - configure argument error.]) + AC_MSG_ERROR([gdal-config not found - configure argument error. ${GENERIC_INSTALL_MESSAGE}]) fi AC_MSG_CHECKING(gdal-config executable) if test -x "${GDAL_CONFIG}"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) - AC_MSG_ERROR([gdal-config not executable.]) + AC_MSG_ERROR([gdal-config not executable. ${GENERIC_INSTALL_MESSAGE}]) fi fi @@ -89,19 +94,7 @@ then GDAL_DATADIR=`${GDAL_CONFIG} --datadir` AC_MSG_RESULT(yes) else - AC_MSG_RESULT(no) - echo "Error: gdal-config not found" - echo "The gdal-config script distributed with GDAL could not be found." - echo "If you have not installed the GDAL libraries, you can" - echo "download the source from http://www.gdal.org/" - echo "If you have installed the GDAL libraries, then make sure that" - echo "gdal-config is in your path. Try typing gdal-config at a" - echo "shell prompt and see if it runs. If not, use:" - echo " --configure-args='--with-gdal-config=/usr/local/bin/gdal-config'" - echo "with appropriate values for your installation." - echo "" - - exit 1 + AC_MSG_ERROR([gdal-config not found. ${GENERIC_INSTALL_MESSAGE}]) fi AC_MSG_NOTICE([GDAL: ${GDAL_VERSION}]) @@ -137,7 +130,7 @@ CPPFLAGS="${INCPPFLAGS} ${PKG_CPPFLAGS}" gdalok=yes AC_CHECK_HEADERS(gdal.h,,gdalok=no) if test "${gdalok}" = no; then - AC_MSG_ERROR([gdal.h not found in given locations.]) + AC_MSG_ERROR([gdal.h not found in given locations. ${GENERIC_INSTALL_MESSAGE}]) fi NEED_DEPS=no @@ -183,7 +176,7 @@ fi if test "${gdalok}" = no; then cat errors.txt AC_MSG_NOTICE([Install failure: compilation and/or linkage problems.]) - AC_MSG_ERROR([GDALAllRegister not found in libgdal.]) + AC_MSG_ERROR([GDALAllRegister not found in libgdal. ${GENERIC_INSTALL_MESSAGE}]) fi rm -f gdal_test errors.txt gdal_test.cpp @@ -414,7 +407,7 @@ if test "${PROJH}" = no; then proj4ok=yes AC_CHECK_LIB(proj,pj_init_plus,,proj4ok=no) if test "${proj4ok}" = no; then - AC_MSG_ERROR([libproj not found in standard or given locations.]) + AC_MSG_ERROR([libproj not found in standard or given locations. ${GENERIC_INSTALL_MESSAGE}]) fi [cat > proj_conf_test.c <<_EOCONF #include @@ -448,7 +441,7 @@ _EOCONF] AC_MSG_RESULT(yes) fi if test "${proj6ok}" = no; then - AC_MSG_ERROR([libproj or sqlite3 not found in standard or given locations.]) + AC_MSG_ERROR([libproj or sqlite3 not found in standard or given locations. ${GENERIC_INSTALL_MESSAGE}]) fi [cat > proj_conf_test.c <<_EOCONF @@ -658,7 +651,7 @@ if test ["$GEOS_CONFIG_SET" = "no"] ; then AC_PATH_PROG([GEOS_CONFIG], ["$GEOS_CONFIG"],["no"]) if test ["$GEOS_CONFIG" = "no"] ; then AC_MSG_RESULT(no) - AC_MSG_ERROR([geos-config not found or not executable.]) + AC_MSG_ERROR([geos-config not found or not executable. ${GENERIC_INSTALL_MESSAGE}]) fi else AC_MSG_CHECKING(geos-config exists) @@ -666,14 +659,14 @@ else AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) - AC_MSG_ERROR([geos-config not found - configure argument error.]) + AC_MSG_ERROR([geos-config not found - configure argument error. ${GENERIC_INSTALL_MESSAGE}]) fi AC_MSG_CHECKING(geos-config executable) if test -x "${GEOS_CONFIG}"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) - AC_MSG_ERROR([geos-config not executable.]) + AC_MSG_ERROR([geos-config not executable. ${GENERIC_INSTALL_MESSAGE}]) fi fi @@ -717,7 +710,7 @@ LIBS="${LIBS} ${PKG_LIBS}" geosok=yes AC_CHECK_HEADERS(geos_c.h,,geosok=no) if test "${geosok}" = no; then - AC_MSG_ERROR([geos_c.h not found in given locations.]) + AC_MSG_ERROR([geos_c.h not found in given locations. ${GENERIC_INSTALL_MESSAGE}]) fi [cat > geos_test.cpp <<_EOCONF @@ -759,7 +752,7 @@ if test "${geosok}" = no; then AC_MSG_RESULT(no) cat errors.txt AC_MSG_NOTICE([Install failure: compilation and/or linkage problems.]) - AC_MSG_ERROR([initGEOS_r not found in libgeos_c.]) + AC_MSG_ERROR([initGEOS_r not found in libgeos_c. ${GENERIC_INSTALL_MESSAGE}]) else AC_SUBST([PKG_LIBS], ["${PKG_LIBS} ${GEOS_DEP_CLIBS}"]) AC_MSG_RESULT(yes) From 50f705fd791211cc24f0e14bdcccdcd42ffcb50e Mon Sep 17 00:00:00 2001 From: edzer Date: Mon, 2 Dec 2024 22:40:42 +0100 Subject: [PATCH 35/43] version --- DESCRIPTION | 2 +- inst/docker/gdal/Dockerfile | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 524b856a2..00d9a4f88 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: sf -Version: 1.0-19 +Version: 1.0-20 Title: Simple Features for R Authors@R: c(person(given = "Edzer", diff --git a/inst/docker/gdal/Dockerfile b/inst/docker/gdal/Dockerfile index d6d82bc7b..d9b41cadb 100644 --- a/inst/docker/gdal/Dockerfile +++ b/inst/docker/gdal/Dockerfile @@ -79,7 +79,7 @@ RUN wget -q http://download.osgeo.org/geos/geos-${GEOS_VERSION}.tar.bz2 \ #RUN git clone --depth 1 https://github.com/OSGeo/PROJ.git # https://download.osgeo.org/proj/proj-9.0.0RC1.tar.gz -ENV PROJ_VERSION 9.4.1 +ENV PROJ_VERSION 9.5.1 RUN wget -q http://download.osgeo.org/proj/proj-${PROJ_VERSION}.tar.gz RUN tar zxvf proj-${PROJ_VERSION}.tar.gz RUN cd proj* \ @@ -101,7 +101,7 @@ RUN cd proj* \ # GDAL: ENV GDAL_VERSION 3.10.0 -ENV GDAL_VERSION_NAME 3.10.0beta1 +ENV GDAL_VERSION_NAME 3.10.0 #https://download.osgeo.org/gdal/3.9.0/gdal-3.9.0beta1.tar.gz #https://download.osgeo.org/gdal/3.10.0/gdal-3.10.0beta1.tar.gz @@ -130,9 +130,9 @@ RUN R CMD INSTALL sf RUN R CMD INSTALL lwgeom RUN R CMD INSTALL stars # -#RUN R CMD check --no-build-vignettes --no-manual --as-cran sf_*.tar.gz -#RUN R CMD check --no-build-vignettes --no-manual --as-cran lwgeom_*.tar.gz +RUN R CMD check --no-build-vignettes --no-manual --as-cran sf_*.tar.gz +RUN R CMD check --no-build-vignettes --no-manual --as-cran lwgeom_*.tar.gz # -#RUN Rscript -e 'options(timeout=1200); install.packages("starsdata", repos="http://cran.uni-muenster.de/pebesma/")' +RUN Rscript -e 'options(timeout=1200); install.packages("starsdata", repos="http://cran.uni-muenster.de/pebesma/")' # -#RUN _R_CHECK_FORCE_SUGGESTS_=false R CMD check --no-build-vignettes --no-manual --as-cran stars_*.tar.gz +RUN _R_CHECK_FORCE_SUGGESTS_=false R CMD check --no-build-vignettes --no-manual --as-cran stars_*.tar.gz From 79964cccdd9c8303261e8edfd726591e0346fca0 Mon Sep 17 00:00:00 2001 From: edzer Date: Sat, 14 Dec 2024 13:42:55 +0100 Subject: [PATCH 36/43] catch polygon full logic error; see #2490 --- R/crs.R | 3 +++ R/sfc.R | 2 +- tests/full.R | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/R/crs.R b/R/crs.R index 15053645e..6d2772b6e 100644 --- a/R/crs.R +++ b/R/crs.R @@ -218,6 +218,9 @@ make_crs = function(x) { if (!is.na(start_crs) && !is.na(end_crs) && start_crs != end_crs) warning("st_crs<- : replacing crs does not reproject data; use st_transform for that", call. = FALSE) + if (is.na(end_crs) && !is.na(start_crs) && isTRUE(st_is_longlat(start_crs)) && any(st_is_full(x))) + stop("To set the crs to NA, first remove the full polygons; see: st_is_full()") + structure(x, crs = end_crs) } diff --git a/R/sfc.R b/R/sfc.R index 6a422abef..e59bd0a8b 100644 --- a/R/sfc.R +++ b/R/sfc.R @@ -656,5 +656,5 @@ st_is_full.sf = function(x, ...) { #' @export #' @name st_is_full st_is_full.bbox = function(x, ...) { - sf_use_s2() && st_is_longlat(x) && all(x == c(-180,-90,180,90)) + isTRUE(sf_use_s2() && st_is_longlat(x) && all(x == c(-180,-90,180,90))) } diff --git a/tests/full.R b/tests/full.R index 8aace5c0f..619683622 100644 --- a/tests/full.R +++ b/tests/full.R @@ -14,8 +14,7 @@ st_bbox(f[2]) st_is_valid(f) # full polygon NA: right, we don't know the CRS st_crs(f) = 'OGC:CRS84' # geodetic: st_is_valid(f) -st_crs(f) = NA -try(st_make_valid(f)) +try(st_set_crs(f, NA)) # errors st_crs(f) = 'OGC:CRS84' # geodetic: st_make_valid(f) # mixed geometries: From f92a064f27ba3941c6334e2e0bd1520d50938833 Mon Sep 17 00:00:00 2001 From: edzer Date: Sat, 14 Dec 2024 13:51:41 +0100 Subject: [PATCH 37/43] clean test output --- tests/full.Rout.save | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/full.Rout.save b/tests/full.Rout.save index 341bf9263..121995400 100644 --- a/tests/full.Rout.save +++ b/tests/full.Rout.save @@ -1,5 +1,5 @@ -R version 4.4.1 (2024-06-14) -- "Race for Your Life" +R version 4.4.2 (2024-10-31) -- "Pile of Leaves" Copyright (C) 2024 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu @@ -56,10 +56,9 @@ xmin ymin xmax ymax > st_crs(f) = 'OGC:CRS84' # geodetic: > st_is_valid(f) [1] TRUE TRUE -> st_crs(f) = NA -> try(st_make_valid(f)) -Error in (function (msg) : - IllegalArgumentException: Invalid number of points in LinearRing found 2 - must be 0 or >= 3 +> try(st_set_crs(f, NA)) # errors +Error in `st_crs<-.sfc`(`*tmp*`, value = value) : + To set the crs to NA, first remove the full polygons; see: st_is_full() > st_crs(f) = 'OGC:CRS84' # geodetic: > st_make_valid(f) Geometry set for 2 features @@ -147,4 +146,4 @@ Units: [m] > > proc.time() user system elapsed - 0.746 1.417 0.668 + 0.770 1.374 0.670 From 338fdc394efa02646387c2aa5b2d9da606aba78e Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 7 Jan 2025 16:47:11 +0100 Subject: [PATCH 38/43] add news --- NEWS.md | 3 +++ inst/docker/gdal/Dockerfile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a93338295..9206fc31c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # version 1.0-20 +* `st_buffer()` for geodetic coordinates allows `max_dist` and `min_level` + to be specified by feature; #2488 and https://github.com/r-spatial/s2/pull/264 + * `distinct.sf()` allows for comparing exact equality of geometries when `exact = TRUE`; #2484 * `st_minimum_bounding_circle()` returns geometries representing the smallest circle that contains the input; #2473 diff --git a/inst/docker/gdal/Dockerfile b/inst/docker/gdal/Dockerfile index d9b41cadb..a47c6a3e6 100644 --- a/inst/docker/gdal/Dockerfile +++ b/inst/docker/gdal/Dockerfile @@ -100,8 +100,8 @@ RUN cd proj* \ # && cd - # GDAL: -ENV GDAL_VERSION 3.10.0 -ENV GDAL_VERSION_NAME 3.10.0 +ENV GDAL_VERSION 3.10.1 +ENV GDAL_VERSION_NAME 3.10.1rc1 #https://download.osgeo.org/gdal/3.9.0/gdal-3.9.0beta1.tar.gz #https://download.osgeo.org/gdal/3.10.0/gdal-3.10.0beta1.tar.gz From eda227c19553397c5b283c538c3320b866ea31e6 Mon Sep 17 00:00:00 2001 From: Roger Bivand Date: Tue, 7 Jan 2025 17:30:08 +0100 Subject: [PATCH 39/43] add OSGeo software DOIs to DESCRIPTION --- DESCRIPTION | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 00d9a4f88..66c5e688a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -48,10 +48,12 @@ Authors@R: comment = c(ORCID = "0000-0002-9415-4582")) ) Description: Support for simple features, a standardized way to - encode spatial vector data. Binds to 'GDAL' for reading and writing - data, to 'GEOS' for geometrical operations, and to 'PROJ' for - projection conversions and datum transformations. Uses by default the 's2' - package for spherical geometry operations on ellipsoidal (long/lat) coordinates. + encode spatial vector data. Binds to 'GDAL' + for reading and writing data, to 'GEOS' + for geometrical operations, and to 'PROJ' + for projection conversions and datum transformations. Uses by default + the 's2' package for spherical geometry operations on ellipsoidal + (long/lat) coordinates. License: GPL-2 | MIT + file LICENSE URL: https://r-spatial.github.io/sf/, https://github.com/r-spatial/sf BugReports: https://github.com/r-spatial/sf/issues From 89640c6d099278184f965ba5634b9658ce322af4 Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 7 Jan 2025 19:31:03 +0100 Subject: [PATCH 40/43] tidy --- DESCRIPTION | 15 ++++++++------- inst/docker/gdal/Dockerfile | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 66c5e688a..aeddd7084 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -47,13 +47,14 @@ Authors@R: role = "ctb", comment = c(ORCID = "0000-0002-9415-4582")) ) -Description: Support for simple features, a standardized way to - encode spatial vector data. Binds to 'GDAL' - for reading and writing data, to 'GEOS' - for geometrical operations, and to 'PROJ' - for projection conversions and datum transformations. Uses by default - the 's2' package for spherical geometry operations on ellipsoidal - (long/lat) coordinates. +Description: Support for simple feature access, a standardized way to + encode and analyze spatial vector data. Binds to 'GDAL' for reading and writing data, to 'GEOS' + for geometrical operations, + and to 'PROJ' for projection + conversions and datum transformations. Uses by default the 's2' + package for geometry operations on geodetic (long/lat degree) + coordinates. License: GPL-2 | MIT + file LICENSE URL: https://r-spatial.github.io/sf/, https://github.com/r-spatial/sf BugReports: https://github.com/r-spatial/sf/issues diff --git a/inst/docker/gdal/Dockerfile b/inst/docker/gdal/Dockerfile index a47c6a3e6..23edd4522 100644 --- a/inst/docker/gdal/Dockerfile +++ b/inst/docker/gdal/Dockerfile @@ -135,4 +135,4 @@ RUN R CMD check --no-build-vignettes --no-manual --as-cran lwgeom_*.tar.gz # RUN Rscript -e 'options(timeout=1200); install.packages("starsdata", repos="http://cran.uni-muenster.de/pebesma/")' # -RUN _R_CHECK_FORCE_SUGGESTS_=false R CMD check --no-build-vignettes --no-manual --as-cran stars_*.tar.gz +#RUN _R_CHECK_FORCE_SUGGESTS_=false R CMD check --no-build-vignettes --no-manual --as-cran stars_*.tar.gz From cf894c38af57522d397d1ee6724bd7db2614bf35 Mon Sep 17 00:00:00 2001 From: edzer Date: Tue, 7 Jan 2025 19:59:49 +0100 Subject: [PATCH 41/43] anticipate gdal 3.10.1, for stars::read_stars() --- src/gdal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gdal.cpp b/src/gdal.cpp index 1653aca79..08e67a656 100644 --- a/src/gdal.cpp +++ b/src/gdal.cpp @@ -71,6 +71,7 @@ void unset_error_handler(void) void CPL_gdal_init() { CPLSetErrorHandler((CPLErrorHandler)__err_handler); + CPLSetConfigOption("GDAL_NETCDF_REPORT_EXTRA_DIM_VALUES", "YES"); GDALAllRegister(); OGRRegisterAll(); } From b70654537f96740f8c3c74e74ded9055f2595ce4 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:58:09 +0100 Subject: [PATCH 42/43] clarification in vignette 7 regarding `lwgeom` --- vignettes/sf7.Rmd | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/vignettes/sf7.Rmd b/vignettes/sf7.Rmd index 09ce83ec6..47a461ddd 100644 --- a/vignettes/sf7.Rmd +++ b/vignettes/sf7.Rmd @@ -56,7 +56,7 @@ coordinates, meaning that they are associated to points on a flat space, or to unprojected or _geographic_ coordinates, when they refer to angles (latitude, longitude) pointing to locations on a sphere (or ellipsoid). The flat space is also referred to as $R^2$, -the sphere as $S^2$ +the sphere as $S^2$. Package `sf` implements _simple features_, a standard for point, line, and polygon geometries where geometries are built from points @@ -68,7 +68,7 @@ to $R^2$, the two-dimensional flat space. Yet, more and more data are routinely served or exchanged using geographic coordinates. Using software that assumes an $R^2$, flat -space may work for some problems, and although `sf` up to version 0.9-x +space may work for some problems, and although `sf` had some functions in place for spherical/ellipsoidal computations (from package `lwgeom`, for computing area, length, distance, and for segmentizing), it has also happily warned @@ -252,6 +252,12 @@ sf_use_s2(TRUE) # Measures +This section compares the differences in results between the `s2` +and `lwgeom` (`sf_use_s2(FALSE)`) packages for calculating area, +length and distance using geographic coordinates. Note that engaging +the `GEOS` engine would require reprojection of the vector layer +to the planar coordinate system (e.g. `EPGS:3857`). + ## Area ```{r eval=require("lwgeom", quietly = TRUE)} options(s2_oriented = FALSE) # correct orientation from here on @@ -276,10 +282,9 @@ sf_use_s2(FALSE) l2 = st_length(nc_ls) plot(l1 , l2) abline(0, 1) -summary((l1-l2)/l1) +summary((l1 - l2)/l1) ``` - ## Distances ```{r} sf_use_s2(TRUE) @@ -288,7 +293,7 @@ sf_use_s2(FALSE) d2 = st_distance(nc, nc[1:10,]) plot(as.vector(d1), as.vector(d2)) abline(0, 1) -summary(as.vector(d1)-as.vector(d2)) +summary(as.vector(d1) - as.vector(d2)) ``` # Predicates From f3e22e2649876d5f2e6dfe3453dc9e402386e8c6 Mon Sep 17 00:00:00 2001 From: Krzysztof Dyba <35004826+kadyb@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:02:17 +0100 Subject: [PATCH 43/43] change "had" to "has" --- vignettes/sf7.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/sf7.Rmd b/vignettes/sf7.Rmd index 47a461ddd..fd95c7981 100644 --- a/vignettes/sf7.Rmd +++ b/vignettes/sf7.Rmd @@ -69,7 +69,7 @@ to $R^2$, the two-dimensional flat space. Yet, more and more data are routinely served or exchanged using geographic coordinates. Using software that assumes an $R^2$, flat space may work for some problems, and although `sf` -had some functions in place for spherical/ellipsoidal computations +has some functions in place for spherical/ellipsoidal computations (from package `lwgeom`, for computing area, length, distance, and for segmentizing), it has also happily warned the user that it is doing $R^2$, flat computations with such coordinates with messages like