BERATools 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. beratools/__init__.py +3 -0
  2. beratools/core/__init__.py +0 -0
  3. beratools/core/algo_centerline.py +476 -0
  4. beratools/core/algo_common.py +489 -0
  5. beratools/core/algo_cost.py +185 -0
  6. beratools/core/algo_dijkstra.py +492 -0
  7. beratools/core/algo_footprint_rel.py +693 -0
  8. beratools/core/algo_line_grouping.py +941 -0
  9. beratools/core/algo_merge_lines.py +255 -0
  10. beratools/core/algo_split_with_lines.py +296 -0
  11. beratools/core/algo_vertex_optimization.py +451 -0
  12. beratools/core/constants.py +56 -0
  13. beratools/core/logger.py +92 -0
  14. beratools/core/tool_base.py +126 -0
  15. beratools/gui/__init__.py +11 -0
  16. beratools/gui/assets/BERALogo.png +0 -0
  17. beratools/gui/assets/beratools.json +471 -0
  18. beratools/gui/assets/closed.gif +0 -0
  19. beratools/gui/assets/closed.png +0 -0
  20. beratools/gui/assets/gui.json +8 -0
  21. beratools/gui/assets/open.gif +0 -0
  22. beratools/gui/assets/open.png +0 -0
  23. beratools/gui/assets/tool.gif +0 -0
  24. beratools/gui/assets/tool.png +0 -0
  25. beratools/gui/bt_data.py +485 -0
  26. beratools/gui/bt_gui_main.py +700 -0
  27. beratools/gui/main.py +27 -0
  28. beratools/gui/tool_widgets.py +730 -0
  29. beratools/tools/__init__.py +7 -0
  30. beratools/tools/canopy_threshold_relative.py +769 -0
  31. beratools/tools/centerline.py +127 -0
  32. beratools/tools/check_seed_line.py +48 -0
  33. beratools/tools/common.py +622 -0
  34. beratools/tools/line_footprint_absolute.py +203 -0
  35. beratools/tools/line_footprint_fixed.py +480 -0
  36. beratools/tools/line_footprint_functions.py +884 -0
  37. beratools/tools/line_footprint_relative.py +75 -0
  38. beratools/tools/tool_template.py +72 -0
  39. beratools/tools/vertex_optimization.py +57 -0
  40. beratools-0.1.0.dist-info/METADATA +134 -0
  41. beratools-0.1.0.dist-info/RECORD +44 -0
  42. beratools-0.1.0.dist-info/WHEEL +4 -0
  43. beratools-0.1.0.dist-info/entry_points.txt +2 -0
  44. beratools-0.1.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,126 @@
1
+ """
2
+ Copyright (C) 2025 Applied Geospatial Research Group.
3
+
4
+ This script is licensed under the GNU General Public License v3.0.
5
+ See <https://gnu.org/licenses/gpl-3.0> for full license details.
6
+
7
+ Author: Richard Zeng
8
+
9
+ Description:
10
+ This script is part of the BERA Tools.
11
+ Webpage: https://github.com/appliedgrg/beratools
12
+
13
+ The purpose of this script is to provide fundamental utilities for tools.
14
+ """
15
+
16
+ import concurrent.futures as con_futures
17
+ import warnings
18
+ from multiprocessing.pool import Pool
19
+
20
+ import geopandas as gpd
21
+ import pandas as pd
22
+ from tqdm.auto import tqdm
23
+
24
+ import beratools.core.constants as bt_const
25
+
26
+ warnings.simplefilter(action="ignore", category=FutureWarning)
27
+
28
+
29
+ class ToolBase(object):
30
+ """Base class for tools."""
31
+
32
+ def __init__(self):
33
+ pass
34
+
35
+ def execute_multiprocessing(self):
36
+ pass
37
+
38
+
39
+ def result_is_valid(result):
40
+ if type(result) is list or type(result) is tuple:
41
+ if len(result) > 0:
42
+ return True
43
+ elif (
44
+ type(result) is pd.DataFrame
45
+ or type(result) is gpd.GeoDataFrame
46
+ or type(result) is pd.Series
47
+ or type(result) is gpd.GeoSeries
48
+ ):
49
+ if not result.empty:
50
+ return True
51
+ elif result:
52
+ return True
53
+
54
+ return False
55
+
56
+
57
+ def print_msg(app_name, step, total_steps):
58
+ print(f' "PROGRESS_LABEL {app_name} {step} of {total_steps}" ', flush=True)
59
+ print(f" %{step / total_steps * 100} ", flush=True)
60
+
61
+
62
+ def execute_multiprocessing(
63
+ in_func,
64
+ in_data,
65
+ app_name,
66
+ processes,
67
+ mode=bt_const.PARALLEL_MODE,
68
+ verbose=False,
69
+ ):
70
+ out_result = []
71
+ step = 0
72
+ total_steps = len(in_data)
73
+
74
+ try:
75
+ if mode == bt_const.ParallelMode.MULTIPROCESSING:
76
+ print("Multiprocessing started...", flush=True)
77
+ print("Using {} CPU cores".format(processes), flush=True)
78
+
79
+ with Pool(processes) as pool:
80
+ with tqdm(total=total_steps, disable=verbose) as pbar:
81
+ for result in pool.imap_unordered(in_func, in_data):
82
+ if result_is_valid(result):
83
+ out_result.append(result)
84
+
85
+ step += 1
86
+ if verbose:
87
+ print_msg(app_name, step, total_steps)
88
+ else:
89
+ pbar.update()
90
+
91
+ pool.close()
92
+ pool.join()
93
+ elif mode == bt_const.ParallelMode.SEQUENTIAL:
94
+ print("Sequential processing started...", flush=True)
95
+ with tqdm(total=total_steps, disable=verbose) as pbar:
96
+ for line in in_data:
97
+ result_item = in_func(line)
98
+ if result_is_valid(result_item):
99
+ out_result.append(result_item)
100
+
101
+ step += 1
102
+ if verbose:
103
+ print_msg(app_name, step, total_steps)
104
+ else:
105
+ pbar.update()
106
+ elif mode == bt_const.ParallelMode.CONCURRENT:
107
+ print("Concurrent processing started...", flush=True)
108
+ print("Using {} CPU cores".format(processes), flush=True)
109
+ with con_futures.ProcessPoolExecutor(max_workers=processes) as executor:
110
+ futures = [executor.submit(in_func, line) for line in in_data]
111
+ with tqdm(total=total_steps, disable=verbose) as pbar:
112
+ for future in con_futures.as_completed(futures):
113
+ result_item = future.result()
114
+ if result_is_valid(result_item):
115
+ out_result.append(result_item)
116
+
117
+ step += 1
118
+ if verbose:
119
+ print_msg(app_name, step, total_steps)
120
+ else:
121
+ pbar.update()
122
+ except Exception as e:
123
+ print(e)
124
+ return None
125
+
126
+ return out_result
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Top-level package for BERA Tools."""
4
+ from beratools.gui.bt_gui_main import *
5
+
6
+ name = 'gui'
7
+
8
+
9
+ def gui_main():
10
+ runner()
11
+
Binary file
@@ -0,0 +1,471 @@
1
+ {
2
+ "toolbox": [
3
+ {
4
+ "category": "Mapping",
5
+ "description": "Tools used to map center lines and footprint polygons of linear disturbances in forests using a Canopy Height Model (CHM) as reference.",
6
+ "tools": [
7
+ {
8
+ "name": "Check Seed Lines",
9
+ "info": "Check seed line quality and fix issues if present.",
10
+ "tool_type": "python",
11
+ "tool_api": "check_seed_line",
12
+ "icon": "check_seed_line.gif",
13
+ "tech_link": "https://appliedgrg.github.io/beratools/check_seed_line.html",
14
+ "parameters": [
15
+ {
16
+ "variable": "in_line",
17
+ "label": "Seed Line",
18
+ "description": "Input seed line file.",
19
+ "type": "vector",
20
+ "subtype": "shp",
21
+ "layer": "in_layer",
22
+ "default": "",
23
+ "output": false,
24
+ "optional": false
25
+ },
26
+ {
27
+ "variable": "out_line",
28
+ "label": "Output Seed Line",
29
+ "description": "Output Seed Line file.",
30
+ "type": "vector",
31
+ "subtype": "shp",
32
+ "layer": "out_layer",
33
+ "default": "",
34
+ "output": true,
35
+ "optional": false
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "name": "Centerline",
41
+ "info": "Extract the least cost path and smooth centerline between vertices of the seed lines.",
42
+ "tool_type": "python",
43
+ "tool_api": "centerline",
44
+ "icon": "centerline.gif",
45
+ "tech_link": "https://appliedgrg.github.io/beratools/centerline.html",
46
+ "parameters": [
47
+ {
48
+ "variable": "in_line",
49
+ "label": "Seed Line",
50
+ "description": "Input seed lines.",
51
+ "type": "vector",
52
+ "subtype": "shp",
53
+ "layer": "in_layer",
54
+ "default": "",
55
+ "output": false,
56
+ "optional": false
57
+ },
58
+ {
59
+ "variable": "in_raster",
60
+ "label": "CHM Raster",
61
+ "description": "Input raster image used to calculate the centerline.",
62
+ "type": "raster",
63
+ "subtype": "tif",
64
+ "default": "",
65
+ "output": false,
66
+ "optional": false
67
+ },
68
+ {
69
+ "variable": "line_radius",
70
+ "label": "Line Processing Radius",
71
+ "description": "Maximum processing distance from input lines. A large search radius may increase processing times whereas a small radius may cause undesired clipping.",
72
+ "type": "number",
73
+ "subtype": "float",
74
+ "default": 15.0,
75
+ "output": false,
76
+ "optional": true
77
+ },
78
+ {
79
+ "variable": "proc_segments",
80
+ "label": "Process Segments",
81
+ "description": "If set to True, will process each segment between each vertex of the input lines separately. If set to False, will process each line from start to end ignoring midpoints. The default is True, since it is assumed that the input lines for this tool are lines manually digitized at regional-scale with sparse vertices at a fine-scale. If using fine-scale (1:1,000) lines as input this may be set to False.",
82
+ "type": "list",
83
+ "subtype": "bool",
84
+ "data": [
85
+ true,
86
+ false
87
+ ],
88
+ "default": true,
89
+ "output": false,
90
+ "optional": false
91
+ },
92
+ {
93
+ "variable": "out_line",
94
+ "label": "Output Centerline",
95
+ "description": "Output centerline file.",
96
+ "type": "vector",
97
+ "subtype": "shp",
98
+ "layer": "out_layer",
99
+ "default": "",
100
+ "output": true,
101
+ "optional": false
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "name": "Vertex Optimization",
107
+ "info": "Relocating line intersections to seismic line paths",
108
+ "tool_type": "python",
109
+ "tool_api": "vertex_optimization",
110
+ "icon": "vertex_optimization.gif",
111
+ "tech_link": "https://appliedgrg.github.io/beratools/vertex_optimization.html",
112
+ "parameters": [
113
+ {
114
+ "variable": "in_line",
115
+ "label": "Input Line",
116
+ "description": "Input lines to optimize.",
117
+ "type": "vector",
118
+ "subtype": "shp",
119
+ "layer": "in_layer",
120
+ "default": "",
121
+ "output": false,
122
+ "optional": false
123
+ },
124
+ {
125
+ "variable": "in_raster",
126
+ "label": "CHM Raster",
127
+ "description": "Input CHM raster used to optimize vertices.",
128
+ "type": "raster",
129
+ "subtype": "tif",
130
+ "default": "",
131
+ "output": false,
132
+ "optional": false
133
+ },
134
+ {
135
+ "variable": "search_distance",
136
+ "label": "Vertex searching distance (m)",
137
+ "description": "Bigger value will let tool enlarge searching area for better vertex location.",
138
+ "type": "number",
139
+ "subtype": "number",
140
+ "default": 30,
141
+ "output": false,
142
+ "optional": false
143
+ },
144
+ {
145
+ "variable": "line_radius",
146
+ "label": "Line Processing Radius",
147
+ "description": "Maximum processing distance from input lines. A large search radius may increase processing times whereas a small radius may cause undesired clipping.",
148
+ "type": "number",
149
+ "subtype": "number",
150
+ "default": 35,
151
+ "output": false,
152
+ "optional": true
153
+ },
154
+ {
155
+ "variable": "out_line",
156
+ "label": "Output Centerline",
157
+ "description": "Output optimized centerline file.",
158
+ "type": "vector",
159
+ "subtype": "shp",
160
+ "layer": "out_layer",
161
+ "default": "",
162
+ "output": true,
163
+ "optional": false
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ "name": "Canopy Footprint (Absolute Threshold)",
169
+ "info": "Creates footprint polygons for each input line based on a least cost corridor method and individual line thresholds.",
170
+ "tool_type": "python",
171
+ "tool_api": "line_footprint_absolute",
172
+ "icon": "line_footprint_absolute.gif",
173
+ "tech_link": "https://appliedgrg.github.io/beratools/line_footprint_abs.html",
174
+ "parameters": [
175
+ {
176
+ "variable": "in_line",
177
+ "label": "Centerline",
178
+ "description": "Input centerline file.",
179
+ "type": "vector",
180
+ "subtype": "shp",
181
+ "layer": "in_layer",
182
+ "default": "",
183
+ "output": false,
184
+ "optional": false
185
+ },
186
+ {
187
+ "variable": "in_chm",
188
+ "label": "CHM Raster",
189
+ "description": "Input CHM image used to calculate the line footprint.",
190
+ "type": "raster",
191
+ "subtype": "tif",
192
+ "default": "",
193
+ "output": false,
194
+ "optional": false
195
+ },
196
+ {
197
+ "variable": "corridor_thresh",
198
+ "label": "Corridor Threshold",
199
+ "description": "The least cost corridor thresholds.",
200
+ "type": "number",
201
+ "subtype": "float",
202
+ "default": 3.0,
203
+ "output": false,
204
+ "optional": true
205
+ },
206
+ {
207
+ "variable": "max_ln_width",
208
+ "label": "Maximum Line Width",
209
+ "description": "Maximum processing width for input lines. A large value may increase processing times whereas a small value may cause undesired clipping.",
210
+ "type": "number",
211
+ "subtype": "float",
212
+ "default": 32.0,
213
+ "output": false,
214
+ "optional": true
215
+ },
216
+ {
217
+ "variable": "exp_shk_cell",
218
+ "label": "Expand And Shrink Cell Range",
219
+ "description": "Range used for cell erosion before final polygons are generated. Useful to remove small artifacts. If the cell size is 1m or larger then set this as zero.",
220
+ "type": "number",
221
+ "subtype": "int",
222
+ "default": 0,
223
+ "output": false,
224
+ "optional": true
225
+ },
226
+ {
227
+ "variable": "out_footprint",
228
+ "label": "Output Footprint",
229
+ "description": "Output footprint polygon file.",
230
+ "type": "vector",
231
+ "subtype": "shp",
232
+ "layer": "out_layer",
233
+ "default": "",
234
+ "output": true,
235
+ "optional": false
236
+ }
237
+ ]
238
+ },
239
+ {
240
+ "name": "Canopy Footprint (Relative Threshold)",
241
+ "info": "Creates dynamic footprint polygons for each input line based on a least cost corridor method and individual line canopy thresholds and cost raster.",
242
+ "tool_type": "python",
243
+ "tool_api": "line_footprint_relative",
244
+ "icon": "line_footprint_relative.gif",
245
+ "tech_link": "https://appliedgrg.github.io/beratools/line_footprint_rel.html",
246
+ "parameters": [
247
+ {
248
+ "variable": "in_line",
249
+ "label": "Centerline",
250
+ "description": "Input line file.",
251
+ "type": "vector",
252
+ "subtype": "shp",
253
+ "default": "",
254
+ "output": false,
255
+ "optional": false
256
+ },
257
+ {
258
+ "variable": "in_chm",
259
+ "label": "CHM Raster",
260
+ "description": "Input raster image used calculate the surrounding forest elevation percentile, create canopy and cost raster.",
261
+ "type": "raster",
262
+ "subtype": "tif",
263
+ "default": "",
264
+ "output": false,
265
+ "optional": false
266
+ },
267
+ {
268
+ "variable": "max_ln_width",
269
+ "label": "Maximum Line Width",
270
+ "description": "Maximum processing width for input lines. A large value may increase processing times whereas a small value may cause undesired clipping.",
271
+ "type": "number",
272
+ "subtype": "float",
273
+ "default": 32.0,
274
+ "output": false,
275
+ "optional": true
276
+ },
277
+ {
278
+ "variable": "exp_shk_cell",
279
+ "label": "Expand And Shrink Cell Range",
280
+ "description": "Range used for cell erosion before final polygons are generated. Useful to remove small artifacts. If the cell size is 1m or larger then set this as zero.",
281
+ "type": "number",
282
+ "subtype": "int",
283
+ "default": 0,
284
+ "output": false,
285
+ "optional": true
286
+ },
287
+ {
288
+ "variable": "out_footprint",
289
+ "label": "Output Footprint Shapefile",
290
+ "description": "Output footprint polygons.",
291
+ "type": "vector",
292
+ "subtype": "shp",
293
+ "default": "",
294
+ "output": true,
295
+ "optional": false
296
+ },
297
+ {
298
+ "variable": "out_centerline",
299
+ "label": "Output Centerline Shapefile",
300
+ "description": "Output centerline polygons.",
301
+ "type": "vector",
302
+ "subtype": "shp",
303
+ "default": "",
304
+ "output": true,
305
+ "optional": true
306
+ },
307
+ {
308
+ "variable": "off_ln_dist",
309
+ "label": "Offset Line Distance",
310
+ "description": "Offset distance from input lines.",
311
+ "type": "number",
312
+ "subtype": "float",
313
+ "default": 10.0,
314
+ "output": false,
315
+ "optional": true
316
+ },
317
+ {
318
+ "variable": "canopy_percentile",
319
+ "label": "Canopy Percentile",
320
+ "description": "The Nth percentile of the surrounding forest.",
321
+ "type": "list",
322
+ "subtype": "int",
323
+ "data": [
324
+ 50,
325
+ 55,
326
+ 60,
327
+ 65,
328
+ 70,
329
+ 75,
330
+ 80,
331
+ 85,
332
+ 90,
333
+ 95
334
+ ],
335
+ "default": 90,
336
+ "output": false,
337
+ "optional": true
338
+ },
339
+ {
340
+ "variable": "canopy_thresh_percentage",
341
+ "label": "Canopy Threshold Percentage",
342
+ "description": "Apply % on calculating Canopy Threshold height from Canopy percentile elevation.",
343
+ "type": "number",
344
+ "subtype": "float",
345
+ "default": 50,
346
+ "output": false,
347
+ "optional": true
348
+ },
349
+ {
350
+ "variable": "tree_radius",
351
+ "label": "Tree Search Radius",
352
+ "description": "Radius of canopy influence in the cost raster. This factor smooths the canopy in the cost raster which helps to prevent gaps in sparsely vegetated areas (e.g. wetlands) to be incorrectly identified as footprint. A large search radius (>=5m) may cause excessive smoothing of the cost raster which can lead to least cost paths ignoring forest-line nuances in sparsely vegetated forests. A small radius (<=1m) may cause the least cost path to cut corners through small gaps in sparse vegetation as well as avoid small obstacles that should not affect overall line shape.",
353
+ "type": "number",
354
+ "subtype": "float",
355
+ "default": 1.5,
356
+ "output": false,
357
+ "optional": true
358
+ },
359
+ {
360
+ "variable": "max_line_dist",
361
+ "label": "Maximum Line Distance",
362
+ "description": "Maximum euclidean distance from canopy. This is a second smoothing factor which helps to position the forest line shape in the center of the line footprint. An excessively small (<=1m) or large (>20m) value may cause the center line to be positioned close to one of the edges of the footprint.",
363
+ "type": "number",
364
+ "subtype": "float",
365
+ "default": 1.5,
366
+ "output": false,
367
+ "optional": true
368
+ },
369
+ {
370
+ "variable": "canopy_avoidance",
371
+ "label": "Canopy Avoidance",
372
+ "description": "Ratio of importance between canopy search radius and euclidean distance. A value close to zero (0) prioritizes search radius whereas a value close to one (1) prioritizes euclidean distance. A small value (<=0.1) may cause the forest lines to miss nuances in sparsely vegetated terrain whereas a big value (>=0.5) may overemphasize turns in complex trails. This factor influences final footprint size in a minor way.",
373
+ "type": "number",
374
+ "subtype": "float",
375
+ "default": 0.0,
376
+ "output": false,
377
+ "optional": true
378
+ },
379
+ {
380
+ "variable": "exponent",
381
+ "label": "Cost Raster Exponent",
382
+ "description": "Affects the cost of vegetated areas in an exponential fashion. A low (<=1) exponent may lead to lines cutting through corners, whereas a large (>=3) exponent may lead to least cost paths completely avoiding narrow lines.",
383
+ "type": "number",
384
+ "subtype": "int",
385
+ "default": 1,
386
+ "output": false,
387
+ "optional": true
388
+ }
389
+ ]
390
+ },
391
+ {
392
+ "name": "Ground Footprint (Fixed Width)",
393
+ "info": "Generating fixed width line footprint",
394
+ "tool_type": "python",
395
+ "tool_api": "line_footprint_fixed",
396
+ "icon": "line_footprint_fixed.gif",
397
+ "tech_link": "https://appliedgrg.github.io/beratools/line_footprint_fixed.html",
398
+ "parameters": [
399
+ {
400
+ "variable": "in_line",
401
+ "label": "Centerline",
402
+ "description": "Input centerline file.",
403
+ "type": "vector",
404
+ "subtype": "shp",
405
+ "layer": "in_layer",
406
+ "default": "",
407
+ "output": false,
408
+ "optional": false
409
+ },
410
+ {
411
+ "variable": "in_footprint",
412
+ "label": "Input Footprint",
413
+ "description": "Input footprint.",
414
+ "type": "vector",
415
+ "subtype": "shp",
416
+ "layer": "in_layer_fp",
417
+ "default": "",
418
+ "output": false,
419
+ "optional": false
420
+ },
421
+ {
422
+ "variable": "n_samples",
423
+ "label": "Sampling number",
424
+ "description": "Sampling number for each line.",
425
+ "type": "number",
426
+ "subtype": "int",
427
+ "default": 15,
428
+ "output": false,
429
+ "optional": true
430
+ },
431
+ {
432
+ "variable": "offset",
433
+ "label": "Perpendicular line length",
434
+ "description": "The length of the perpendicular line",
435
+ "type": "number",
436
+ "subtype": "float",
437
+ "default": 30.0,
438
+ "output": false,
439
+ "optional": true
440
+ },
441
+ {
442
+ "variable": "max_width",
443
+ "label": "Use maximum width",
444
+ "description": "Use maximum width",
445
+ "type": "list",
446
+ "subtype": "bool",
447
+ "data": [
448
+ true,
449
+ false
450
+ ],
451
+ "default": true,
452
+ "output": false,
453
+ "optional": true
454
+ },
455
+ {
456
+ "variable": "out_footprint",
457
+ "label": "Output Fixed Footprint",
458
+ "description": "Output fixed width footprint file.",
459
+ "type": "vector",
460
+ "subtype": "shp",
461
+ "layer": "out_layer",
462
+ "default": "",
463
+ "output": true,
464
+ "optional": false
465
+ }
466
+ ]
467
+ }
468
+ ]
469
+ }
470
+ ]
471
+ }
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ {
2
+ "ascii_art": [
3
+ " ____ ____ ____ __ ____ _____ _____ __ ___ \n",
4
+ "( _ \\( ___)( _ \\ /__\\ (_ _)( _ )( _ )( ) / __) \n",
5
+ " ) _ < )__) ) / /(__)\\ )( )(_)( )(_)( )(__ \\__ \\ \n",
6
+ "(____/(____)(_)\\_)(__)(__) (__) (_____)(_____)(____)(___/ \n"
7
+ ]
8
+ }
Binary file
Binary file
Binary file
Binary file