6
6
# ' and boolean operations (e.g., [s2_intersection()]) to specify the model for
7
7
# ' containment and how new geometries should be constructed.
8
8
# '
9
- # ' @param model,polygon_model,polyline_model See section 'Model'
9
+ # ' @param model One of 'open', 'semi-open' (default for polygons),
10
+ # ' or 'closed' (default for polylines). See section 'Model'
10
11
# ' @param snap Use `s2_snap_identity()`, `s2_snap_distance()`, `s2_snap_level()`,
11
12
# ' or `s2_snap_precision()` to specify how or if coordinate rounding should
12
13
# ' occur.
13
14
# ' @param snap_radius As opposed to the snap function, which specifies
14
15
# ' the maximum distance a vertex should move, the snap radius (in radians) sets
15
16
# ' the minimum distance between vertices of the output that don't cause vertices
16
17
# ' to move more than the distance specified by the snap function. This can be used
17
- # ' to simplify the result of a boolean operation.
18
+ # ' to simplify the result of a boolean operation. Use -1 to specify that any
19
+ # ' minimum distance is acceptable.
20
+ # ' @param duplicate_edges Use `TRUE` to keep duplicate edges (e.g., duplicate
21
+ # ' points).
22
+ # ' @param edge_type One of 'directed' (default) or 'undirected'.
23
+ # ' @param polyline_type One of 'path' (default) or 'walk'. If 'walk',
24
+ # ' polylines that backtrack are preserved.
25
+ # ' @param polyline_sibling_pairs One of 'discard' (default) or 'keep'.
26
+ # ' @param simplify_edge_chains Use `TRUE` to remove vertices that are within
27
+ # ' `snap_radius` of the original vertex.
28
+ # ' @param split_crossing_edges Use `TRUE` to split crossing polyline edges
29
+ # ' when creating geometries.
30
+ # ' @param idempotent Use `FALSE` to apply snap even if snapping is not necessary
31
+ # ' to satisfy vertex constraints.
32
+ # ' @param validate Use `TRUE` to validate the result from the builder.
18
33
# ' @param level A value from 0 to 30 corresponding to the cell level
19
34
# ' at which snapping should occur.
20
35
# ' @param distance A distance (in radians) denoting the maximum
25
40
# ' @section Model:
26
41
# ' The geometry model indicates whether or not a geometry includes its boundaries.
27
42
# ' Boundaries of line geometries are its end points.
28
- # ' OPEN geometries do not contain their boundary (`model = 0 `); CLOSED
29
- # ' geometries (`model = 2 `) contain their boundary; HALF-CLOSED geometries
30
- # ' (`model = 1 `) contain half of their boundaries, such that when two polygons
43
+ # ' OPEN geometries do not contain their boundary (`model = "open" `); CLOSED
44
+ # ' geometries (`model = "closed" `) contain their boundary; SEMI-OPEN geometries
45
+ # ' (`model = "semi-open" `) contain half of their boundaries, such that when two polygons
31
46
# ' do not overlap or two lines do not cross, no point exist that belong to
32
47
# ' more than one of the geometries. (This latter form, half-closed, is
33
48
# ' not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on
34
- # ' which that is based). A value of -1 does not set the model, leaving the
35
- # ' S2 default (HALF-CLOSED). The default values for [s2_contains()] (0)
36
- # ' and covers/covered_by (2) correspond to the SFA standard specification
49
+ # ' which that is based). The default values for [s2_contains()] (open)
50
+ # ' and covers/covered_by (closed) correspond to the SFA standard specification
37
51
# ' of these operators.
38
52
# '
39
53
# ' @export
40
54
# '
41
55
# ' @examples
42
- # ' # use s2_options() to specify polygon/polyline models
43
- # ' # and/or snap level
44
- # ' s2_options(model = 1 , snap = s2_snap_level(30))
56
+ # ' # use s2_options() to specify containment models, snap level
57
+ # ' # layer creation options, and builder options
58
+ # ' s2_options(model = "closed" , snap = s2_snap_level(30))
45
59
# '
46
- # ' # model value affects boolean operations and binary predicates
47
- # ' # in the open model, lines do not contain endpoints (but do contain other points)
48
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = 0))
49
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = 0))
50
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0.5)", s2_options(model = 0))
51
- # '
52
- # ' # in the semi-open and closed models, endpoints are contained
53
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = 1))
54
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = 1))
55
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = 2))
56
- # ' s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = 2))
57
- # '
58
- # ' # for polygons, boundary points are either contained or not contained depending on
59
- # ' # the model of choice
60
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0 0)", s2_options(model = 0))
61
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0.5 0.75)", s2_options(model = 0))
62
- # '
63
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0 0)", s2_options(model = 1))
64
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0.5 0.75)", s2_options(model = 1))
65
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0 0)", s2_options(model = 2))
66
- # ' s2_contains("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0.5 0.75)", s2_options(model = 2))
67
- # '
68
- # ' # s2_dwithin(x, y, epsilon) is a more explicit test if boundaries are important
69
- # ' s2_dwithin(
70
- # ' "LINESTRING (0 0, 0 1, 1 1)",
71
- # ' c("POINT (0 0)", "POINT (0 1)", "POINT (0 0.5)"),
72
- # ' 1e-7
73
- # ' )
74
- # '
75
- s2_options <- function (model = - 1 , snap = s2_snap_identity(), snap_radius = - 1 ,
76
- polygon_model = model , polyline_model = model ) {
60
+ s2_options <- function (model = NULL ,
61
+ snap = s2_snap_identity(),
62
+ snap_radius = - 1 ,
63
+ duplicate_edges = FALSE ,
64
+ edge_type = " directed" ,
65
+ validate = FALSE ,
66
+ polyline_type = " path" ,
67
+ polyline_sibling_pairs = " keep" ,
68
+ simplify_edge_chains = FALSE ,
69
+ split_crossing_edges = FALSE ,
70
+ idempotent = FALSE ) {
71
+ # check snap radius (passing in a huge snap radius can cause problems)
72
+ if (snap_radius > 3 ) {
73
+ stop(
74
+ " Snap radius is too large. Did you pass in a snap radius in meters instead of radians?" ,
75
+ call. = FALSE
76
+ )
77
+ }
78
+
77
79
structure(
78
80
list (
79
- polygon_model = polygon_model ,
80
- polyline_model = polyline_model ,
81
+ # model needs to be "unset" by default because there are differences in polygon
82
+ # and polyline handling by default that are good defaults to preserve
83
+ model = if (is.null(model )) - 1 else match_option(model , c(" open" , " semi-open" , " closed" ), " model" ),
81
84
snap = snap ,
82
- snap_radius = snap_radius
85
+ snap_radius = snap_radius ,
86
+ duplicate_edges = duplicate_edges ,
87
+ edge_type = match_option(edge_type , c(" directed" , " undirected" ), " edge_type" ),
88
+ validate = validate ,
89
+ polyline_type = match_option(polyline_type , c(" path" , " walk" ), " polyline_type" ),
90
+ polyline_sibling_pairs = match_option(
91
+ polyline_sibling_pairs ,
92
+ c(" discard" , " keep" ),
93
+ " polyline_sibling_pairs"
94
+ ),
95
+ simplify_edge_chains = simplify_edge_chains ,
96
+ split_crossing_edges = split_crossing_edges ,
97
+ idempotent = idempotent
83
98
),
84
99
class = " s2_options"
85
100
)
@@ -94,6 +109,10 @@ s2_snap_identity <- function() {
94
109
# ' @rdname s2_options
95
110
# ' @export
96
111
s2_snap_level <- function (level ) {
112
+ if (level > 30 ) {
113
+ stop(" `level` must be an intger between 1 and 30" , call. = FALSE )
114
+ }
115
+
97
116
structure(list (level = level ), class = " snap_level" )
98
117
}
99
118
@@ -108,3 +127,16 @@ s2_snap_precision <- function(precision) {
108
127
s2_snap_distance <- function (distance ) {
109
128
structure(list (distance = distance ), class = " snap_distance" )
110
129
}
130
+
131
+
132
+ match_option <- function (x , options , arg ) {
133
+ result <- match(x , options )
134
+ if (identical(result , NA_integer_ )) {
135
+ stop(
136
+ sprintf(" `%s` must be one of %s" , arg , paste0(' "' , options , ' "' , collapse = " , " )),
137
+ call. = FALSE
138
+ )
139
+ }
140
+
141
+ result
142
+ }
0 commit comments