@@ -57,7 +57,7 @@ def _cb_res(ctx, param, value):
57
57
def _cb_dist (ctx , param , value ):
58
58
59
59
"""
60
- Click callback to ensure `--dist ` can be either a float or a field name.
60
+ Click callback to ensure `--distance ` can be either a float or a field name.
61
61
"""
62
62
63
63
try :
@@ -69,7 +69,7 @@ def _cb_dist(ctx, param, value):
69
69
def _processor (args ):
70
70
71
71
"""
72
- Process a single feature
72
+ Process a single feature.
73
73
74
74
Parameters
75
75
----------
@@ -102,7 +102,13 @@ def _processor(args):
102
102
103
103
# Support buffering by a field's value
104
104
if not isinstance (buf_args ['distance' ], (float , int )):
105
- buf_args ['distance' ] = feat ['properties' ][buf_args ['distance' ]]
105
+ field_val = feat ['properties' ][buf_args ['distance' ]]
106
+
107
+ # Buffering according to a field but field is None so just return the feature
108
+ if field_val is None :
109
+ return feat
110
+ else :
111
+ buf_args ['distance' ] = field_val
106
112
107
113
try :
108
114
# src_crs -> buf_crs
@@ -123,7 +129,7 @@ def _processor(args):
123
129
return feat
124
130
125
131
except Exception :
126
- logger .exception ("Feature with ID %s failed" , feat .get ('id' ))
132
+ logger .exception ("Feature with ID %s failed during buffering " , feat .get ('id' ))
127
133
if not skip_failures :
128
134
raise
129
135
@@ -133,56 +139,61 @@ def _processor(args):
133
139
@click .argument ('infile' , required = True )
134
140
@click .argument ('outfile' , required = True )
135
141
@click .option (
136
- '-f' , '--format' , '--driver' , metavar = 'NAME' , required = True ,
137
- help = "Output driver name."
142
+ '-f' , '--format' , '--driver' , metavar = 'NAME' ,
143
+ help = "Output driver name. Derived from the input datasource if not given. "
138
144
)
139
145
@click .option (
140
- '--cap-style' , type = click .Choice (['flat' , 'round' , 'square' ]), default = 'round' ,
141
- callback = _cb_cap_style , help = "Where geometries terminate, use this style. (default: round)"
146
+ '--cap-style' , type = click .Choice (['flat' , 'round' , 'square' ]),
147
+ default = 'round' , show_default = True ,
148
+ callback = _cb_cap_style , help = "Where geometries terminate, use this style."
142
149
)
143
150
@click .option (
144
- '--join-style' , type = click .Choice (['round' , 'mitre' , 'bevel' ]), default = 'round' ,
145
- callback = _cb_join_style , help = "Where geometries touch, use this style. (default: round)"
151
+ '--join-style' , type = click .Choice (['round' , 'mitre' , 'bevel' ]),
152
+ default = 'round' , show_default = True ,
153
+ callback = _cb_join_style , help = "Where geometries touch, use this style."
146
154
)
147
155
@click .option (
148
- '--res' , type = click .INT , callback = _cb_res , default = 16 ,
149
- help = "Resolution of the buffer around each vertex of the object. (default: 16) "
156
+ '--res' , type = click .INT , callback = _cb_res , default = 16 , show_default = True ,
157
+ help = "Resolution of the buffer around each vertex of the geometry. "
150
158
)
151
159
@click .option (
152
- '--mitre-limit' , type = click .FLOAT , default = 5.0 ,
160
+ '--mitre-limit' , type = click .FLOAT , default = 5.0 , show_default = True ,
153
161
help = "When using a mitre join, limit the maximum length of the join corner according to "
154
- "this ratio. (default: 0.5) "
162
+ "this ratio."
155
163
)
156
164
@click .option (
157
- '--dist' , metavar = 'FLOAT | FIELD' , required = True , callback = _cb_dist ,
158
- help = "Buffer distance in georeferenced units according to --buf-dist."
165
+ '--distance' , metavar = 'FLOAT|FIELD' , required = True , callback = _cb_dist ,
166
+ help = "Buffer distance or field containing distance values. Units match --buf-crs. "
167
+ "When buffering with a field, feature's with a null value are unaltered."
159
168
)
160
169
@click .option (
161
170
'--src-crs' , help = "Specify CRS for input data. Not needed if set in input file."
162
171
)
163
172
@click .option (
164
- '--buf-crs' , help = "Perform buffer operations in a different CRS. ( default: --src-crs) "
173
+ '--buf-crs' , help = "Perform buffer operations in a different CRS. [ default: --src-crs] "
165
174
)
166
175
@click .option (
167
176
'--dst-crs' , help = "Reproject geometries to a different CRS before writing. Must be "
168
- "combined with --buf-crs. ( default: --src-crs) "
177
+ "combined with --buf-crs. [ default: --src-crs] "
169
178
)
170
179
@click .option (
171
- '--otype' , 'output_geom_type' , default = 'MultiPolygon' , metavar = 'GEOMTYPE' ,
172
- help = "Specify output geometry type. (default: MultiPolygon)"
180
+ '--geom-type' , 'output_geom_type' , default = 'MultiPolygon' ,
181
+ metavar = 'GEOMTYPE' , show_default = True ,
182
+ help = "Output layer's geometry type."
173
183
)
174
184
@click .option (
175
185
'--skip-failures' , is_flag = True ,
176
186
help = "Skip geometries that fail somewhere in the processing pipeline."
177
187
)
178
188
@click .option (
179
- '--jobs' , type = click .IntRange (1 , cpu_count ()), default = 1 , metavar = "CORES" ,
180
- help = "Process geometries in parallel across N cores. The goal of this flag is speed so "
181
- "feature order and ID's are not preserved. (default: 1)"
189
+ '--jobs' , type = click .IntRange (1 , cpu_count ()), default = 1 ,
190
+ metavar = "CORES" , show_default = True ,
191
+ help = "Process geometries in parallel across N cores. Feature ID's and order are not "
192
+ "preserved if more that 1 cores are used."
182
193
)
183
194
@click .pass_context
184
195
def buffer (ctx , infile , outfile , driver , cap_style , join_style , res , mitre_limit ,
185
- dist , src_crs , buf_crs , dst_crs , output_geom_type , skip_failures , jobs ):
196
+ distance , src_crs , buf_crs , dst_crs , output_geom_type , skip_failures , jobs ):
186
197
187
198
"""
188
199
Geometries can be dilated with a positive distance, eroded with a negative
@@ -195,31 +206,31 @@ def buffer(ctx, infile, outfile, driver, cap_style, join_style, res, mitre_limit
195
206
Default settings - buffer geometries in the input CRS:
196
207
197
208
\b
198
- $ fio buffer in.geojson out.geojson --dist 10
209
+ $ fio buffer in.geojson out.geojson --distance 10
199
210
200
- Dynamically buffer geometries by a distance stored in the field ` magnitude`
211
+ Dynamically buffer geometries by a distance stored in the field ' magnitude'
201
212
and write as GeoJSON:
202
213
203
214
\b
204
215
$ fio buffer \\
205
216
in.shp \\
206
217
out.geojson \\
207
218
--driver GeoJSON \\
208
- --dist magnitude
219
+ --distance magnitude
209
220
210
221
Read geometries from one CRS, buffer in another, and then write to a third:
211
222
212
223
\b
213
224
$ fio buffer in.shp out.shp \\
214
- --dist 10 \\
225
+ --distance 10 \\
215
226
--buf-crs EPSG:3857 \\
216
227
--dst-crs EPSG:32618
217
228
218
229
Control cap style, mitre limit, segment resolution, and join style:
219
230
220
231
\b
221
232
$ fio buffer in.geojson out.geojson \\
222
- --dist 0.1 \\
233
+ --distance 0.1 \\
223
234
--res 5 \\
224
235
--cap-style flat \\
225
236
--join-style mitre \\
@@ -235,15 +246,15 @@ def buffer(ctx, infile, outfile, driver, cap_style, join_style, res, mitre_limit
235
246
if isinstance (getattr (ctx , 'obj' ), dict ):
236
247
logger .setLevel (ctx .obj .get ('verbosity' , 1 ))
237
248
238
- with fio .open (infile , 'r' ) as src :
249
+ with fio .open (infile ) as src :
239
250
240
251
logger .debug ("Resolving CRS fall backs" )
241
252
242
253
src_crs = src_crs or src .crs
243
254
buf_crs = buf_crs or src_crs
244
255
dst_crs = dst_crs or src_crs
245
256
246
- if src_crs is None :
257
+ if not src_crs :
247
258
raise click .ClickException (
248
259
"CRS is not set in input file. Use --src-crs to specify." )
249
260
@@ -266,7 +277,7 @@ def buffer(ctx, infile, outfile, driver, cap_style, join_style, res, mitre_limit
266
277
267
278
# Keyword arguments for `<Geometry>.buffer()`
268
279
buf_args = {
269
- 'distance' : dist ,
280
+ 'distance' : distance ,
270
281
'resolution' : res ,
271
282
'cap_style' : cap_style ,
272
283
'join_style' : join_style ,
@@ -287,6 +298,12 @@ def buffer(ctx, infile, outfile, driver, cap_style, join_style, res, mitre_limit
287
298
logger .debug ("Starting processing on %s cores" , jobs )
288
299
for o_feat in Pool (jobs ).imap_unordered (_processor , task_generator ):
289
300
if o_feat is not None :
290
- dst .write (o_feat )
301
+ try :
302
+ dst .write (o_feat )
303
+ except Exception :
304
+ logger .exception (
305
+ "Feature with ID %s failed during write" , o_feat .get ('id' ))
306
+ if not skip_failures :
307
+ raise
291
308
292
309
logger .debug ("Finished processing." )
0 commit comments