sf_use_s2() # check current engine[1] TRUE
RΒ² (flat)
SΒ² (sphere)
s2 R packagesf version 1.0 (2021), geographic coordinates automatically use s2 instead of GEOS.st_area(), st_length(), st_distance(), st_buffer(), all predicatesSame two endpoints β completely different rendering:
The same polygon, the same point β different answer:
Sparse geometry binary predicate list of length 1, where the predicate
was `contains'
1: (empty)
In RΒ²: a polygon ring encloses a bounded area. The outside extends to infinity β obviously βoutside.β
In SΒ²: a ring on a sphere divides it into exactly two finite regions. There is no infinity. Which side is βinsideβ depends entirely on ring direction.
# Same 4 corners β different winding order
sq_ccw <- st_sfc(st_polygon(list(matrix( # CCW β small region
c(-10,-10, 10,-10, 10,10, -10,10, -10,-10),
ncol = 2, byrow = TRUE))), crs = 4326)
sq_cw <- st_sfc(st_polygon(list(matrix( # CW β large region
c(-10,-10, -10,10, 10,10, 10,-10, -10,-10),
ncol = 2, byrow = TRUE))), crs = 4326)| Ring | RΒ² behaviour | SΒ² behaviour |
|---|---|---|
| CCW exterior | Standard polygon | Small-side interior |
| CW exterior | Invalid / hole | Large-side interior |
st_as_s2(x, oriented = FALSE) auto-corrects ring direction, assuming the intended interior is less than half the sphere
You are building a global land cover database. One of the classes is ocean.
How would you represent the ocean as a geometry in a GIS?
Discuss in pairs. Consider:
The ocean is the complement of all land polygons β it has no outer boundary, only inner ones.
In RΒ²: impossible to represent directly (unbounded exterior).
In SΒ²: the whole sphere is a valid polygon.
[1] 0.288699
Adjacent polygons share an edge. Under SΒ² (or GEOS with model = "closed"):
[,1] [,2] [,3]
[1,] TRUE TRUE FALSE
[2,] TRUE TRUE TRUE
[3,] FALSE TRUE TRUE
The model parameter controls boundary inclusion:
| Model | Boundary belongs to | Use when |
|---|---|---|
"closed" (default) |
Both polygons | Spatial filters, overlap detection |
"open" |
Neither polygon | Points strictly inside only |
"semi-open" |
Exactly one polygon | Coverage operations, point-in-polygon counts, raster analogy |
The semi-open model mirrors how raster grids work: each cell owns its upper-left corner and upper/left edges β no gaps, no double-counting.
For typical geographic analyses: negligible.
| Measure | Relative difference (s2 vs flat) | Absolute example |
|---|---|---|
| Area | Β±0.007% | ~7 kmΒ² per 100 000 kmΒ² |
| Length | Β±0.013% | ~13 m per 100 km |
| Distance | up to ~0.5% | ~1β2 km over 500 km |
For continental or global scale: not negligible. The antimeridian is the clearest failure case.
Rule of thumb:
Your colleague downloads Swiss municipality boundaries in EPSG:4326 and runs:
Some municipalities on cantonal borders appear in two cantons and their population is counted twice.
model = "closed" is actually the right choice?Discuss in groups
No external sources β reason from what you know about s2 boundary models