1
1
use crate :: geometry:: Coord ;
2
2
use crate :: GeoNum ;
3
- use i_overlay:: core:: fill_rule:: FillRule ;
4
- use i_overlay:: core:: overlay:: ShapeType ;
5
- use i_overlay:: core:: overlay_rule:: OverlayRule ;
6
- use i_overlay:: string:: clip:: ClipRule ;
3
+ use i_overlay:: i_float:: float:: compatible:: FloatPointCompatible ;
4
+ use i_overlay:: i_float:: float:: number:: FloatNumber ;
7
5
8
- pub trait BoolOpsCoord < T > : Copy {
9
- fn new ( x : T , y : T ) -> Self ;
10
- fn x ( & self ) -> T ;
11
- fn y ( & self ) -> T ;
12
- }
13
-
14
- /// A geometry coordinate number suitable for performing geometric boolean operations.
15
- pub trait BoolOpsNum : GeoNum {
16
- type CoordType : BoolOpsCoord < Self > ;
17
- type OverlayType : BoolOpsOverlay < CoordType = Self :: CoordType > ;
18
- type StringOverlayType : BoolOpsStringOverlay < CoordType = Self :: CoordType > ;
19
-
20
- fn to_bops_coord ( geo_coord : Coord < Self > ) -> Self :: CoordType {
21
- Self :: CoordType :: new ( geo_coord. x , geo_coord. y )
22
- }
23
-
24
- fn to_geo_coord ( bops_coord : Self :: CoordType ) -> Coord < Self > {
25
- Coord {
26
- x : bops_coord. x ( ) ,
27
- y : bops_coord. y ( ) ,
28
- }
29
- }
30
- }
31
-
32
- pub trait BoolOpsOverlay {
33
- type CoordType ;
34
- type OverlayGraph : BoolOpsOverlayGraph < CoordType = Self :: CoordType > ;
35
- fn new ( ) -> Self ;
36
- fn add_path ( & mut self , path : Vec < Self :: CoordType > , shape_type : ShapeType ) ;
37
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: OverlayGraph ;
38
- }
39
-
40
- pub ( super ) trait BoolOpsOverlayGraph {
41
- type CoordType ;
42
- fn extract_shapes ( & self , overlay_rule : OverlayRule ) -> Vec < Vec < Vec < Self :: CoordType > > > ;
43
- }
44
-
45
- pub trait BoolOpsStringOverlay {
46
- type CoordType ;
47
- type StringGraph : BoolOpsStringGraph < CoordType = Self :: CoordType > ;
48
- fn new ( ) -> Self ;
49
- fn add_shape_path ( & mut self , path : Vec < Self :: CoordType > ) ;
50
- fn add_string_line ( & mut self , path : [ Self :: CoordType ; 2 ] ) ;
51
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: StringGraph ;
52
- }
53
-
54
- pub ( super ) trait BoolOpsStringGraph {
55
- type CoordType ;
56
- fn clip_string_lines ( & self , clip_rule : ClipRule ) -> Vec < Vec < Self :: CoordType > > ;
57
- }
58
-
59
- mod f64 {
60
- use super :: { ClipRule , FillRule , OverlayRule , ShapeType } ;
61
- use i_overlay:: f64:: {
62
- graph:: F64OverlayGraph ,
63
- overlay:: F64Overlay ,
64
- string:: { F64StringGraph , F64StringOverlay } ,
65
- } ;
66
- use i_overlay:: i_float:: f64_point:: F64Point ;
67
-
68
- impl super :: BoolOpsNum for f64 {
69
- type CoordType = F64Point ;
70
- type OverlayType = F64Overlay ;
71
- type StringOverlayType = F64StringOverlay ;
72
- }
73
-
74
- impl super :: BoolOpsCoord < f64 > for F64Point {
75
- #[ inline]
76
- fn new ( x : f64 , y : f64 ) -> Self {
77
- Self :: new ( x, y)
78
- }
79
-
80
- #[ inline]
81
- fn x ( & self ) -> f64 {
82
- self . x
83
- }
84
-
85
- #[ inline]
86
- fn y ( & self ) -> f64 {
87
- self . y
88
- }
89
- }
90
-
91
- impl super :: BoolOpsOverlay for F64Overlay {
92
- type CoordType = F64Point ;
93
- type OverlayGraph = F64OverlayGraph ;
94
-
95
- #[ inline]
96
- fn new ( ) -> Self {
97
- Self :: new ( )
98
- }
99
-
100
- #[ inline]
101
- fn add_path ( & mut self , path : Vec < F64Point > , shape_type : ShapeType ) {
102
- self . add_path ( path, shape_type)
103
- }
104
-
105
- #[ inline]
106
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: OverlayGraph {
107
- self . into_graph ( fill_rule)
108
- }
109
- }
110
-
111
- impl super :: BoolOpsOverlayGraph for F64OverlayGraph {
112
- type CoordType = F64Point ;
113
-
114
- #[ inline]
115
- fn extract_shapes ( & self , overlay_rule : OverlayRule ) -> Vec < Vec < Vec < F64Point > > > {
116
- self . extract_shapes ( overlay_rule)
117
- }
118
- }
119
-
120
- impl super :: BoolOpsStringOverlay for F64StringOverlay {
121
- type CoordType = F64Point ;
122
- type StringGraph = F64StringGraph ;
123
-
124
- #[ inline]
125
- fn new ( ) -> Self {
126
- Self :: new ( )
127
- }
6
+ /// A geometry coordinate scalar suitable for performing geometric boolean operations.
7
+ pub trait BoolOpsNum : GeoNum + FloatNumber { }
8
+ impl < T : GeoNum + FloatNumber > BoolOpsNum for T { }
128
9
129
- #[ inline]
130
- fn add_shape_path ( & mut self , path : Vec < Self :: CoordType > ) {
131
- self . add_shape_path ( path)
132
- }
133
-
134
- #[ inline]
135
- fn add_string_line ( & mut self , path : [ Self :: CoordType ; 2 ] ) {
136
- self . add_string_line ( path)
137
- }
10
+ /// New type for `Coord` that implements `FloatPointCompatible` for `BoolOpsNum` to
11
+ /// circumvent orphan rule, since Coord is defined in geo_types.
12
+ #[ derive( Copy , Clone , Debug ) ]
13
+ pub struct BoolOpsCoord < T : BoolOpsNum > ( pub ( crate ) Coord < T > ) ;
138
14
139
- #[ inline]
140
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: StringGraph {
141
- self . into_graph ( fill_rule)
142
- }
15
+ impl < T : BoolOpsNum > FloatPointCompatible < T > for BoolOpsCoord < T > {
16
+ fn from_xy ( x : T , y : T ) -> Self {
17
+ Self ( Coord { x, y } )
143
18
}
144
19
145
- impl super :: BoolOpsStringGraph for F64StringGraph {
146
- type CoordType = F64Point ;
147
-
148
- #[ inline]
149
- fn clip_string_lines ( & self , clip_rule : ClipRule ) -> Vec < Vec < Self :: CoordType > > {
150
- self . clip_string_lines ( clip_rule)
151
- }
20
+ fn x ( & self ) -> T {
21
+ self . 0 . x
152
22
}
153
- }
154
-
155
- mod f32 {
156
- use i_overlay:: core:: fill_rule:: FillRule ;
157
- use i_overlay:: core:: overlay:: ShapeType ;
158
- use i_overlay:: core:: overlay_rule:: OverlayRule ;
159
- use i_overlay:: f32:: graph:: F32OverlayGraph ;
160
- use i_overlay:: f32:: overlay:: F32Overlay ;
161
- use i_overlay:: f32:: string:: { F32StringGraph , F32StringOverlay } ;
162
- use i_overlay:: i_float:: f32_point:: F32Point ;
163
- use i_overlay:: string:: clip:: ClipRule ;
164
23
165
- impl super :: BoolOpsNum for f32 {
166
- type CoordType = F32Point ;
167
- type OverlayType = F32Overlay ;
168
- type StringOverlayType = F32StringOverlay ;
169
- }
170
-
171
- impl super :: BoolOpsCoord < f32 > for F32Point {
172
- #[ inline]
173
- fn new ( x : f32 , y : f32 ) -> Self {
174
- Self :: new ( x, y)
175
- }
176
- #[ inline]
177
- fn x ( & self ) -> f32 {
178
- self . x
179
- }
180
- #[ inline]
181
- fn y ( & self ) -> f32 {
182
- self . y
183
- }
184
- }
185
-
186
- impl super :: BoolOpsOverlay for F32Overlay {
187
- type CoordType = F32Point ;
188
- type OverlayGraph = F32OverlayGraph ;
189
-
190
- #[ inline]
191
- fn new ( ) -> Self {
192
- Self :: new ( )
193
- }
194
-
195
- #[ inline]
196
- fn add_path ( & mut self , path : Vec < Self :: CoordType > , shape_type : ShapeType ) {
197
- self . add_path ( path, shape_type)
198
- }
199
-
200
- #[ inline]
201
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: OverlayGraph {
202
- self . into_graph ( fill_rule)
203
- }
204
- }
205
-
206
- impl super :: BoolOpsOverlayGraph for F32OverlayGraph {
207
- type CoordType = F32Point ;
208
-
209
- #[ inline]
210
- fn extract_shapes ( & self , overlay_rule : OverlayRule ) -> Vec < Vec < Vec < F32Point > > > {
211
- self . extract_shapes ( overlay_rule)
212
- }
213
- }
214
-
215
- impl super :: BoolOpsStringOverlay for F32StringOverlay {
216
- type CoordType = F32Point ;
217
- type StringGraph = F32StringGraph ;
218
-
219
- #[ inline]
220
- fn new ( ) -> Self {
221
- Self :: new ( )
222
- }
223
-
224
- #[ inline]
225
- fn add_shape_path ( & mut self , path : Vec < Self :: CoordType > ) {
226
- self . add_shape_path ( path)
227
- }
228
-
229
- #[ inline]
230
- fn add_string_line ( & mut self , path : [ Self :: CoordType ; 2 ] ) {
231
- self . add_string_line ( path)
232
- }
233
-
234
- #[ inline]
235
- fn into_graph ( self , fill_rule : FillRule ) -> Self :: StringGraph {
236
- self . into_graph ( fill_rule)
237
- }
238
- }
239
-
240
- impl super :: BoolOpsStringGraph for F32StringGraph {
241
- type CoordType = F32Point ;
242
-
243
- #[ inline]
244
- fn clip_string_lines ( & self , clip_rule : ClipRule ) -> Vec < Vec < Self :: CoordType > > {
245
- self . clip_string_lines ( clip_rule)
246
- }
24
+ fn y ( & self ) -> T {
25
+ self . 0 . y
247
26
}
248
27
}
249
28
250
29
pub ( super ) mod convert {
251
30
use super :: super :: OpType ;
252
- use super :: { BoolOpsNum , OverlayRule } ;
31
+ use super :: BoolOpsNum ;
32
+ use crate :: bool_ops:: i_overlay_integration:: BoolOpsCoord ;
253
33
use crate :: geometry:: { LineString , MultiLineString , MultiPolygon , Polygon } ;
34
+ use i_overlay:: core:: overlay_rule:: OverlayRule ;
254
35
255
- pub fn line_string_from_path < T : BoolOpsNum > ( path : Vec < T :: CoordType > ) -> LineString < T > {
256
- let coords = path. into_iter ( ) . map ( T :: to_geo_coord ) ;
257
- LineString ( coords. collect ( ) )
36
+ pub fn line_string_from_path < T : BoolOpsNum > ( path : Vec < BoolOpsCoord < T > > ) -> LineString < T > {
37
+ let coords = path. into_iter ( ) . map ( |bops_coord| bops_coord . 0 ) . collect ( ) ;
38
+ LineString ( coords)
258
39
}
259
40
260
41
pub fn multi_line_string_from_paths < T : BoolOpsNum > (
261
- paths : Vec < Vec < T :: CoordType > > ,
42
+ paths : Vec < Vec < BoolOpsCoord < T > > > ,
262
43
) -> MultiLineString < T > {
263
44
let line_strings = paths. into_iter ( ) . map ( |p| line_string_from_path ( p) ) ;
264
45
MultiLineString ( line_strings. collect ( ) )
265
46
}
266
47
267
- pub fn polygon_from_shape < T : BoolOpsNum > ( shape : Vec < Vec < T :: CoordType > > ) -> Polygon < T > {
48
+ pub fn polygon_from_shape < T : BoolOpsNum > ( shape : Vec < Vec < BoolOpsCoord < T > > > ) -> Polygon < T > {
268
49
let mut rings = shape. into_iter ( ) . map ( |p| line_string_from_path ( p) ) ;
269
50
let exterior = rings. next ( ) . unwrap_or ( LineString :: new ( vec ! [ ] ) ) ;
270
51
Polygon :: new ( exterior, rings. collect ( ) )
271
52
}
272
53
273
54
pub fn multi_polygon_from_shapes < T : BoolOpsNum > (
274
- shapes : Vec < Vec < Vec < T :: CoordType > > > ,
55
+ shapes : Vec < Vec < Vec < BoolOpsCoord < T > > > > ,
275
56
) -> MultiPolygon < T > {
276
57
let polygons = shapes. into_iter ( ) . map ( |s| polygon_from_shape ( s) ) ;
277
58
MultiPolygon ( polygons. collect ( ) )
278
59
}
279
60
280
- pub fn ring_to_shape_path < T : BoolOpsNum > ( line_string : & LineString < T > ) -> Vec < T :: CoordType > {
61
+ pub fn ring_to_shape_path < T : BoolOpsNum > ( line_string : & LineString < T > ) -> Vec < BoolOpsCoord < T > > {
281
62
if line_string. 0 . is_empty ( ) {
282
63
return vec ! [ ] ;
283
64
}
284
65
// In geo, Polygon rings are explicitly closed LineStrings — their final coordinate is the same as their first coordinate,
285
66
// however in i_overlay, shape paths are implicitly closed, so we skip the last coordinate.
286
67
let coords = & line_string. 0 [ ..line_string. 0 . len ( ) - 1 ] ;
287
- coords. iter ( ) . copied ( ) . map ( T :: to_bops_coord ) . collect ( )
68
+ coords. iter ( ) . copied ( ) . map ( BoolOpsCoord ) . collect ( )
288
69
}
289
70
290
71
impl From < OpType > for OverlayRule {
@@ -308,15 +89,15 @@ mod tests {
308
89
#[ test]
309
90
fn two_empty_polygons ( ) {
310
91
let p1: Polygon = wkt ! ( POLYGON EMPTY ) ;
311
- let p2 = wkt ! ( POLYGON EMPTY ) ;
92
+ let p2: Polygon = wkt ! ( POLYGON EMPTY ) ;
312
93
assert_eq ! ( & p1. union ( & p2) , & wkt!( MULTIPOLYGON EMPTY ) ) ;
313
94
assert_eq ! ( & p1. intersection( & p2) , & wkt!( MULTIPOLYGON EMPTY ) ) ;
314
95
}
315
96
316
97
#[ test]
317
98
fn one_empty_polygon ( ) {
318
99
let p1: Polygon = wkt ! ( POLYGON ( ( 0. 0. , 0. 1. , 1. 1. , 1. 0. , 0. 0. ) ) ) ;
319
- let p2 = wkt ! ( POLYGON EMPTY ) ;
100
+ let p2: Polygon = wkt ! ( POLYGON EMPTY ) ;
320
101
assert_eq ! ( & p1. union ( & p2) , & MultiPolygon ( vec![ p1. clone( ) ] ) ) ;
321
102
assert_eq ! ( & p1. intersection( & p2) , & wkt!( MULTIPOLYGON EMPTY ) ) ;
322
103
}
0 commit comments