BERATools 0.2.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 (142) hide show
  1. beratools/__init__.py +9 -0
  2. beratools/core/__init__.py +0 -0
  3. beratools/core/algo_centerline.py +351 -0
  4. beratools/core/constants.py +86 -0
  5. beratools/core/dijkstra_algorithm.py +460 -0
  6. beratools/core/logger.py +85 -0
  7. beratools/core/tool_base.py +133 -0
  8. beratools/gui/__init__.py +15 -0
  9. beratools/gui/batch_processing_dlg.py +463 -0
  10. beratools/gui/beratools.json +2300 -0
  11. beratools/gui/bt_data.py +487 -0
  12. beratools/gui/bt_gui_main.py +691 -0
  13. beratools/gui/cli.py +18 -0
  14. beratools/gui/gui.json +8 -0
  15. beratools/gui/img/BERALogo.png +0 -0
  16. beratools/gui/img/closed.gif +0 -0
  17. beratools/gui/img/closed.png +0 -0
  18. beratools/gui/img/open.gif +0 -0
  19. beratools/gui/img/open.png +0 -0
  20. beratools/gui/img/tool.gif +0 -0
  21. beratools/gui/img/tool.png +0 -0
  22. beratools/gui/map_window.py +146 -0
  23. beratools/gui/tool_widgets.py +493 -0
  24. beratools/gui_tk/ASCII Banners.txt +248 -0
  25. beratools/gui_tk/__init__.py +20 -0
  26. beratools/gui_tk/beratools_main.py +515 -0
  27. beratools/gui_tk/bt_widgets.py +442 -0
  28. beratools/gui_tk/cli.py +18 -0
  29. beratools/gui_tk/gui.json +8 -0
  30. beratools/gui_tk/img/BERALogo.png +0 -0
  31. beratools/gui_tk/img/closed.gif +0 -0
  32. beratools/gui_tk/img/closed.png +0 -0
  33. beratools/gui_tk/img/open.gif +0 -0
  34. beratools/gui_tk/img/open.png +0 -0
  35. beratools/gui_tk/img/tool.gif +0 -0
  36. beratools/gui_tk/img/tool.png +0 -0
  37. beratools/gui_tk/main.py +14 -0
  38. beratools/gui_tk/map_window.py +144 -0
  39. beratools/gui_tk/runner.py +1481 -0
  40. beratools/gui_tk/tooltip.py +55 -0
  41. beratools/third_party/pyqtlet2/__init__.py +9 -0
  42. beratools/third_party/pyqtlet2/leaflet/__init__.py +26 -0
  43. beratools/third_party/pyqtlet2/leaflet/control/__init__.py +6 -0
  44. beratools/third_party/pyqtlet2/leaflet/control/control.py +59 -0
  45. beratools/third_party/pyqtlet2/leaflet/control/draw.py +52 -0
  46. beratools/third_party/pyqtlet2/leaflet/control/layers.py +20 -0
  47. beratools/third_party/pyqtlet2/leaflet/core/Parser.py +24 -0
  48. beratools/third_party/pyqtlet2/leaflet/core/__init__.py +2 -0
  49. beratools/third_party/pyqtlet2/leaflet/core/evented.py +180 -0
  50. beratools/third_party/pyqtlet2/leaflet/layer/__init__.py +5 -0
  51. beratools/third_party/pyqtlet2/leaflet/layer/featuregroup.py +34 -0
  52. beratools/third_party/pyqtlet2/leaflet/layer/icon/__init__.py +1 -0
  53. beratools/third_party/pyqtlet2/leaflet/layer/icon/icon.py +30 -0
  54. beratools/third_party/pyqtlet2/leaflet/layer/imageoverlay.py +18 -0
  55. beratools/third_party/pyqtlet2/leaflet/layer/layer.py +105 -0
  56. beratools/third_party/pyqtlet2/leaflet/layer/layergroup.py +45 -0
  57. beratools/third_party/pyqtlet2/leaflet/layer/marker/__init__.py +1 -0
  58. beratools/third_party/pyqtlet2/leaflet/layer/marker/marker.py +91 -0
  59. beratools/third_party/pyqtlet2/leaflet/layer/tile/__init__.py +2 -0
  60. beratools/third_party/pyqtlet2/leaflet/layer/tile/gridlayer.py +4 -0
  61. beratools/third_party/pyqtlet2/leaflet/layer/tile/tilelayer.py +16 -0
  62. beratools/third_party/pyqtlet2/leaflet/layer/vector/__init__.py +5 -0
  63. beratools/third_party/pyqtlet2/leaflet/layer/vector/circle.py +15 -0
  64. beratools/third_party/pyqtlet2/leaflet/layer/vector/circlemarker.py +18 -0
  65. beratools/third_party/pyqtlet2/leaflet/layer/vector/path.py +5 -0
  66. beratools/third_party/pyqtlet2/leaflet/layer/vector/polygon.py +14 -0
  67. beratools/third_party/pyqtlet2/leaflet/layer/vector/polyline.py +18 -0
  68. beratools/third_party/pyqtlet2/leaflet/layer/vector/rectangle.py +14 -0
  69. beratools/third_party/pyqtlet2/leaflet/map/__init__.py +1 -0
  70. beratools/third_party/pyqtlet2/leaflet/map/map.py +220 -0
  71. beratools/third_party/pyqtlet2/mapwidget.py +45 -0
  72. beratools/third_party/pyqtlet2/web/custom.js +43 -0
  73. beratools/third_party/pyqtlet2/web/map.html +23 -0
  74. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers-2x.png +0 -0
  75. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers.png +0 -0
  76. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon-2x.png +0 -0
  77. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon.png +0 -0
  78. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-shadow.png +0 -0
  79. beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.css +656 -0
  80. beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.js +6 -0
  81. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.codeclimate.yml +14 -0
  82. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.editorconfig +4 -0
  83. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.gitattributes +22 -0
  84. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.travis.yml +43 -0
  85. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/LICENSE +20 -0
  86. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers-2x.png +0 -0
  87. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers.png +0 -0
  88. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon-2x.png +0 -0
  89. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon.png +0 -0
  90. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-shadow.png +0 -0
  91. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet-2x.png +0 -0
  92. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.png +0 -0
  93. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.svg +156 -0
  94. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.css +10 -0
  95. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.js +10 -0
  96. beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/LICENSE +22 -0
  97. beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/leaflet.rotatedMarker.js +57 -0
  98. beratools/tools/Beratools_r_script.r +1120 -0
  99. beratools/tools/Ht_metrics.py +116 -0
  100. beratools/tools/__init__.py +7 -0
  101. beratools/tools/batch_processing.py +132 -0
  102. beratools/tools/canopy_threshold_relative.py +670 -0
  103. beratools/tools/canopycostraster.py +222 -0
  104. beratools/tools/centerline.py +176 -0
  105. beratools/tools/common.py +885 -0
  106. beratools/tools/fl_regen_csf.py +428 -0
  107. beratools/tools/forest_line_attributes.py +408 -0
  108. beratools/tools/forest_line_ecosite.py +216 -0
  109. beratools/tools/lapis_all.py +103 -0
  110. beratools/tools/least_cost_path_from_chm.py +152 -0
  111. beratools/tools/line_footprint_absolute.py +363 -0
  112. beratools/tools/line_footprint_fixed.py +282 -0
  113. beratools/tools/line_footprint_functions.py +720 -0
  114. beratools/tools/line_footprint_relative.py +64 -0
  115. beratools/tools/ln_relative_metrics.py +615 -0
  116. beratools/tools/r_cal_lpi_elai.r +25 -0
  117. beratools/tools/r_generate_pd_focalraster.r +101 -0
  118. beratools/tools/r_interface.py +80 -0
  119. beratools/tools/r_point_density.r +9 -0
  120. beratools/tools/rpy_chm2trees.py +86 -0
  121. beratools/tools/rpy_dsm_chm_by.py +81 -0
  122. beratools/tools/rpy_dtm_by.py +63 -0
  123. beratools/tools/rpy_find_cellsize.py +43 -0
  124. beratools/tools/rpy_gnd_csf.py +74 -0
  125. beratools/tools/rpy_hummock_hollow.py +85 -0
  126. beratools/tools/rpy_hummock_hollow_raster.py +71 -0
  127. beratools/tools/rpy_las_info.py +51 -0
  128. beratools/tools/rpy_laz2las.py +40 -0
  129. beratools/tools/rpy_lpi_elai_lascat.py +466 -0
  130. beratools/tools/rpy_normalized_lidar_by.py +56 -0
  131. beratools/tools/rpy_percent_above_dbh.py +80 -0
  132. beratools/tools/rpy_points2trees.py +88 -0
  133. beratools/tools/rpy_vegcoverage.py +94 -0
  134. beratools/tools/tiler.py +206 -0
  135. beratools/tools/tool_template.py +54 -0
  136. beratools/tools/vertex_optimization.py +620 -0
  137. beratools/tools/zonal_threshold.py +144 -0
  138. beratools-0.2.0.dist-info/METADATA +63 -0
  139. beratools-0.2.0.dist-info/RECORD +142 -0
  140. beratools-0.2.0.dist-info/WHEEL +4 -0
  141. beratools-0.2.0.dist-info/entry_points.txt +2 -0
  142. beratools-0.2.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,80 @@
1
+ import os
2
+ import time
3
+
4
+ from beratools.tools.common import *
5
+ from beratools.tools.r_interface import *
6
+
7
+ def percentage_aboveDBH(callback, in_las_folder, is_normalized, out_folder, DBH, cell_size, processes, verbose):
8
+ rprocesses = r_processes(processes)
9
+
10
+ # assign R script file to local variable
11
+ Beratools_R_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Beratools_r_script.r')
12
+ # Defining the R script and loading the instance in Python
13
+ r['source'](Beratools_R_script)
14
+ # Loading the function defined in R script.
15
+ r_percentage_aboveDBH = robjects.globalenv['percentage_aboveDBH']
16
+ # Invoking the R function
17
+ r_percentage_aboveDBH(in_las_folder, is_normalized, out_folder, DBH, cell_size, rprocesses)
18
+
19
+
20
+ if __name__ == '__main__':
21
+ start_time = time.time()
22
+ print('Finding percentage returns above DBH height process\n @ {}'
23
+ .format(time.strftime("%d %b %Y %H:%M:%S", time.localtime())))
24
+
25
+ packages = ['lidR', 'future', 'terra']
26
+ check_r_packages_installation(packages)
27
+
28
+ print("Checking input parameters ...")
29
+ in_args, in_verbose = check_arguments()
30
+ in_las_folder = in_args.input["in_las_folder"]
31
+
32
+ try:
33
+ DBH = float(in_args.input["DBH"])
34
+ if DBH < 0:
35
+ raise ValueError
36
+ else:
37
+ in_args.input["DBH"] = DBH
38
+ except ValueError:
39
+ print("Invalid input of DBH, default value is used")
40
+ in_args.input["DBH"] = 1.3
41
+
42
+ try:
43
+ is_normalized = bool(in_args.input["is_normalized"])
44
+
45
+ except ValueError:
46
+ print("Invalid input of checking normalized data box, normalize data will be carried")
47
+ in_args.input["is_normalized"] = False
48
+
49
+ try:
50
+ cell_size = float(in_args.input["cell_size"])
51
+ in_args.input["cell_size"] = cell_size
52
+ except ValueError:
53
+ print("Invalid input of cell size, default value is used")
54
+ in_args.input["cell_size"] = 5.0
55
+
56
+ out_folder = in_args.input["out_folder"]
57
+
58
+ if not os.path.exists(in_las_folder):
59
+ print("Error! Cannot locate Las folder, please check.")
60
+ exit()
61
+ else:
62
+ found = False
63
+ for files in os.listdir(in_las_folder):
64
+ if files.endswith(".las") or files.endswith(".laz"):
65
+ found = True
66
+ break
67
+ if not found:
68
+ print("Error! Cannot locate input LAS file(s), please check!")
69
+ exit()
70
+
71
+ if not os.path.exists(out_folder):
72
+ print("Warning! Cannot locate output folder, It will be created.")
73
+ os.makedirs(out_folder)
74
+
75
+ print("Checking input parameters ... Done")
76
+
77
+ percentage_aboveDBH(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
78
+
79
+ print('Finding percentage returns above DBH height process is done in {} seconds)'
80
+ .format(round(time.time() - start_time, 5)))
@@ -0,0 +1,88 @@
1
+ import os
2
+ import time
3
+
4
+ from beratools.tools.common import *
5
+ from beratools.tools.r_interface import *
6
+
7
+ def points2trees(callback, in_las_folder, is_normalized, hmin, cell_size, do_nCHM, out_folder, processes, verbose):
8
+ rprocesses = r_processes(processes)
9
+
10
+ # assign R script file to local variable
11
+ Beratools_R_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Beratools_r_script.r')
12
+ # Defining the R script and loading the instance in Python
13
+ r['source'](Beratools_R_script)
14
+ # Loading the function defined in R script.
15
+ r_points2trees = robjects.globalenv['points2trees']
16
+ r_pd2cellsize = robjects.globalenv['pd2cellsize']
17
+ # Invoking the R function
18
+ if do_nCHM:
19
+ CHMcell_size = r_pd2cellsize(in_las_folder, rprocesses)
20
+ print("CHM raster output cell size is: {}m".format(CHMcell_size))
21
+ r_points2trees(in_las_folder, is_normalized, hmin, out_folder, rprocesses, CHMcell_size, cell_size)
22
+ else:
23
+ CHMcell_size = -999
24
+ r_points2trees(in_las_folder, is_normalized, hmin, out_folder, rprocesses, CHMcell_size, cell_size)
25
+
26
+
27
+ if __name__ == '__main__':
28
+ start_time = time.time()
29
+ print('Starting tree detection from LAS processing\n @ {}'
30
+ .format(time.strftime("%d %b %Y %H:%M:%S", time.localtime())))
31
+
32
+ packages = ['lidR', 'rgrass', 'rlas', 'future', 'terra', 'sp']
33
+ check_r_packages_installation(packages)
34
+
35
+ print("Checking input parameters ...")
36
+ in_args, in_verbose = check_arguments()
37
+ in_las_folder = in_args.input["in_las_folder"]
38
+
39
+ try:
40
+ hmin = float(in_args.input["hmin"])
41
+ if hmin >= 20:
42
+ print("Invalid input of minimum height (<=20) of a tree, maximum is used")
43
+ in_args.input["hmin"] = 20.0
44
+ else:
45
+ in_args.input["hmin"] = hmin
46
+ except ValueError:
47
+ print("Invalid input of minimum height (<=20) of a tree, default is used")
48
+ in_args.input["hmin"] = 3.0
49
+
50
+ try:
51
+ is_normalized = bool(in_args.input["is_normalized"])
52
+
53
+ except ValueError:
54
+ print("Invalid input of checking normalized data box, normalize data will be carried")
55
+ in_args.input["is_normalized"] = False
56
+
57
+ try:
58
+ cell_size = float(in_args.input["cell_size"])
59
+ in_args.input["cell_size"] = cell_size
60
+ except ValueError:
61
+ print("Invalid input of minimum height of a tree, default is used")
62
+ in_args.input["cell_size"] = 5.0
63
+
64
+ out_folder = in_args.input["out_folder"]
65
+
66
+ if not os.path.exists(in_las_folder):
67
+ print("Error! Cannot locate Las folder, please check.")
68
+ exit()
69
+ else:
70
+ found = False
71
+ for files in os.listdir(in_las_folder):
72
+ if files.endswith(".las") or files.endswith(".laz"):
73
+ found = True
74
+ break
75
+ if not found:
76
+ print("Error! Cannot locate input LAS file(s), please check!")
77
+ exit()
78
+
79
+ if not os.path.exists(out_folder):
80
+ print("Warning! Cannot locate output folder, It will be created.")
81
+ os.makedirs(out_folder)
82
+
83
+ print("Checking input parameters ... Done")
84
+
85
+ points2trees(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
86
+
87
+ print('Tree detection from Lidar data processing is done in {} seconds)'
88
+ .format(round(time.time() - start_time, 5)))
@@ -0,0 +1,94 @@
1
+ import os
2
+ import time
3
+
4
+ from beratools.tools.common import *
5
+ from beratools.tools.r_interface import *
6
+
7
+ def veg_cover_percentage(callback, in_las_folder, is_normalized, out_folder, hmin, hmax, cell_size, processes, verbose):
8
+ rprocesses = r_processes(processes)
9
+
10
+ # assign R script file to local variable
11
+ Beratools_R_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Beratools_r_script.r')
12
+ # Defining the R script and loading the instance in Python
13
+ r['source'](Beratools_R_script)
14
+ # Loading the function defined in R script.
15
+ r_veg_metrics = robjects.globalenv['veg_cover_percentage']
16
+ # Invoking the R function
17
+ r_veg_metrics(in_las_folder, is_normalized, out_folder, hmin, hmax, cell_size, rprocesses)
18
+
19
+
20
+ if __name__ == '__main__':
21
+ start_time = time.time()
22
+ print('Finding Vegetation Coverage from Lidar data process\n @ {}'
23
+ .format(time.strftime("%d %b %Y %H:%M:%S", time.localtime())))
24
+
25
+ packages = ['lidR', 'future', 'terra']
26
+ check_r_packages_installation(packages)
27
+
28
+ print("Checking input parameters ...")
29
+ in_args, in_verbose = check_arguments()
30
+ in_las_folder = in_args.input["in_las_folder"]
31
+
32
+ try:
33
+ hmin = float(in_args.input["hmin"])
34
+ if hmin < 0:
35
+ raise ValueError
36
+ else:
37
+ in_args.input["hmin"] = hmin
38
+ except ValueError:
39
+ print("Invalid input of minimum height of a tree, default value is used")
40
+ in_args.input["hmin"] = 3.0
41
+
42
+ try:
43
+ hmax = float(in_args.input["hmax"])
44
+ if hmax <= hmin:
45
+ raise ValueError
46
+ else:
47
+ in_args.input["hmax"] = hmax
48
+ except ValueError:
49
+ print("Invalid input of maximum height of a tree, default value is used")
50
+ if hmin < 10:
51
+ in_args.input["hmax"] = 10.0
52
+ else:
53
+ in_args.input["hmin"] = 3.0
54
+ in_args.input["hmax"] = 10.0
55
+
56
+ try:
57
+ is_normalized = bool(in_args.input["is_normalized"])
58
+
59
+ except ValueError:
60
+ print("Invalid input of checking normalized data box, normalize data will be carried")
61
+ in_args.input["is_normalized"] = False
62
+
63
+ try:
64
+ cell_size = float(in_args.input["cell_size"])
65
+ in_args.input["cell_size"] = cell_size
66
+ except ValueError:
67
+ print("Invalid input of cell size, default value is used")
68
+ in_args.input["cell_size"] = 5.0
69
+
70
+ out_folder = in_args.input["out_folder"]
71
+
72
+ if not os.path.exists(in_las_folder):
73
+ print("Error! Cannot locate Las folder, please check.")
74
+ exit()
75
+ else:
76
+ found = False
77
+ for files in os.listdir(in_las_folder):
78
+ if files.endswith(".las") or files.endswith(".laz"):
79
+ found = True
80
+ break
81
+ if not found:
82
+ print("Error! Cannot locate input LAS file(s), please check!")
83
+ exit()
84
+
85
+ if not os.path.exists(out_folder):
86
+ print("Warning! Cannot locate output folder, It will be created.")
87
+ os.makedirs(out_folder)
88
+
89
+ print("Checking input parameters ... Done")
90
+
91
+ veg_cover_percentage(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
92
+
93
+ print('Finding Vegetation Coverage from Lidar data process is done in {} seconds)'
94
+ .format(round(time.time() - start_time, 5)))
@@ -0,0 +1,206 @@
1
+ import os
2
+ from qtpy.QtWidgets import QApplication, QDialog
3
+
4
+ from shapely.geometry import Polygon
5
+ from beratools.tools.common import *
6
+ from beratools.gui.map_window import MapWindow
7
+
8
+
9
+ class Tiler:
10
+ def __init__(self, callback, in_line, in_chm, tile_size,
11
+ tile_buffer, out_project, processes, verbose):
12
+
13
+ self.in_line = in_line
14
+ self.in_chm = in_chm
15
+ self.boundary = None
16
+ self.tile_size = float(tile_size)
17
+ self.tile_buffer = float(tile_buffer)
18
+ self.out_project = out_project
19
+ self.processes = processes
20
+ self.verbose = verbose
21
+ self.clip_data = []
22
+ self.proj_path = ''
23
+ self.in_crs = None
24
+ self.out_crs = None
25
+
26
+ def create_out_file_name(self):
27
+ # prepare path
28
+ # TODO: more formats later, now only tiff and shp are considered
29
+ path_chm = Path(self.in_chm)
30
+ path_line = Path(self.in_line)
31
+ self.proj_path = path_chm.parent
32
+ path_root = self.proj_path.joinpath('cells')
33
+
34
+ if not path_root.exists():
35
+ path_root.mkdir()
36
+
37
+ item_count = len(self.clip_data)
38
+ str_len = len(str(item_count))
39
+ for i, item in enumerate(self.clip_data):
40
+ cell_num = str(i).zfill(str_len)
41
+ self.clip_data[i]['raster'] = path_root.joinpath(path_chm.stem + '_' + cell_num + '.tif')
42
+ self.clip_data[i]['line'] = path_root.joinpath(path_line.stem + '_' + cell_num + '.shp')
43
+
44
+ def save_clip_files(self):
45
+ project_data = {'tool_api': 'tiler'}
46
+ tasks_list = []
47
+ step = 0
48
+
49
+ print('Generating {} tiles ...'.format(len(self.clip_data)))
50
+ for item in self.clip_data:
51
+ return_lines = clip_lines(item['geometry'], self.tile_buffer, self.in_line, item['line'])
52
+ return_raster = clip_raster(self.in_chm, item['geometry'], self.tile_buffer, item['raster'])
53
+
54
+ if not return_lines.empty and return_raster:
55
+ cell_data = {
56
+ 'in_line': item['line'].as_posix(),
57
+ 'in_chm': item['raster'].as_posix()
58
+ }
59
+ tasks_list.append(cell_data)
60
+ step += 1
61
+ print('%{}'.format(step / len(self.clip_data) * 100))
62
+
63
+ project_data['tasks'] = tasks_list
64
+ with open(self.out_project, 'w') as project_file:
65
+ json.dump(project_data, project_file, indent=4)
66
+
67
+ def generate_cells(self):
68
+ part_x = 0
69
+ part_y = 0
70
+ width = 0
71
+ height = 0
72
+
73
+ with(rasterio.open(self.in_chm)) as raster:
74
+ self.boundary = raster.bounds
75
+ width = raster.width
76
+ height = raster.height
77
+ self.in_crs = raster.crs
78
+
79
+ if self.boundary:
80
+ part_x = math.ceil(width / self.tile_size)
81
+ part_y = math.ceil(height / self.tile_size)
82
+ min_x, min_y, max_x, max_y = self.boundary
83
+ polygon_bound = Polygon([(min_x, min_y), (min_x, max_y), (max_x, max_y), (max_x, min_y)])
84
+
85
+ step_x = (max_x - min_x) / part_x
86
+ step_y = (max_y - min_y) / part_y
87
+ cells = []
88
+ for i in range(part_x):
89
+ for j in range(part_y):
90
+ cells.append(Polygon([(min_x + i * step_x, min_y + j * step_y),
91
+ (min_x + (i + 1) * step_x, min_y + j * step_y),
92
+ (min_x + (i + 1) * step_x, min_y + (j + 1) * step_y),
93
+ (min_x + i * step_x, min_y + (j + 1) * step_y)]))
94
+
95
+ # remove polygons not in boundary
96
+ for cell in cells:
97
+ if not polygon_bound.disjoint(cell):
98
+ self.clip_data.append({'geometry': cell})
99
+
100
+ return True
101
+
102
+ return False
103
+
104
+ def generate_tiles_info(self):
105
+ tiles_info = {'count': len(self.clip_data), 'dimension': self.tile_size}
106
+ return tiles_info
107
+
108
+ def cells_to_coord_list(self):
109
+ self.out_crs = CRS('EPSG:4326')
110
+ transformer = Transformer.from_crs(self.in_crs, self.out_crs)
111
+ coords_list = []
112
+ if self.clip_data:
113
+ for item in self.clip_data:
114
+ geom = item['geometry']
115
+ coords = mapping(geom)['coordinates']
116
+ if len(coords) > 0:
117
+ wgs84_coords = list(transformer.itransform(coords[0]))
118
+ wgs84_coords = [list(pt) for pt in wgs84_coords]
119
+ coords_list.append(wgs84_coords)
120
+
121
+ # find bounds
122
+ x = [pt[0] for polygon in coords_list for pt in polygon]
123
+ y = [pt[1] for polygon in coords_list for pt in polygon]
124
+ x_min = min(x)
125
+ x_max = max(x)
126
+ y_min = min(y)
127
+ y_max = max(y)
128
+
129
+ center = [(x_min + x_max) / 2, (y_min + y_max) / 2]
130
+
131
+ return coords_list, [[x_min, y_min], [x_max, y_max]], center
132
+
133
+ def shapefile_to_coord_list(self):
134
+ lines = read_geoms_from_shapefile(self.in_line)
135
+ line_coords = []
136
+
137
+ coords_list = []
138
+ for line in lines:
139
+ coords = line['coordinates']
140
+ for pt in coords:
141
+ coords_list.append(list(pt))
142
+
143
+ line_coords.append(coords_list)
144
+
145
+ return line_coords
146
+
147
+ def execute(self):
148
+ if self.generate_cells():
149
+ coords_list, bounds, center = self.cells_to_coord_list()
150
+ map_window = MapWindow()
151
+
152
+ # add lines to map
153
+ # lines = self.shapefile_to_coord_list()
154
+ # map_window.add_polylines_to_map(lines, 'gray')
155
+
156
+ # generate raster footprint and add to the map
157
+ footprint = generate_raster_footprint(self.in_chm)
158
+
159
+ # add AOI polygon and tile polygons
160
+ map_window.set_tiles_info(self.generate_tiles_info())
161
+ map_window.add_polygons_to_map('cells', coords_list, 'magenta')
162
+ map_window.add_polygons_to_map('base', footprint, 'green')
163
+ map_window.set_view(center, 10)
164
+ # bounds = [[56.143426823080134, 111.1130415762259], [56.26141944093645, 110.63627702636289]]
165
+ flag = map_window.exec()
166
+
167
+ if flag != QDialog.Accepted:
168
+ return
169
+
170
+ self.create_out_file_name()
171
+ self.save_clip_files()
172
+
173
+ # save polygons to shapefile
174
+ out_cells_file = self.proj_path.joinpath('cells.shp')
175
+ schema = {
176
+ 'geometry': 'Polygon'
177
+ }
178
+ driver = 'ESRI Shapefile'
179
+ with fiona.open(out_cells_file, 'w', driver, schema, self.in_crs) as out_line_file:
180
+ for item in self.clip_data:
181
+ feature = {
182
+ 'geometry': mapping(item['geometry'])
183
+ }
184
+ out_line_file.write(feature)
185
+
186
+ return
187
+
188
+
189
+ if __name__ == '__main__':
190
+ # supress web engine logging
191
+ os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--enable-logging --log-level=3"
192
+
193
+ app = QApplication(sys.argv)
194
+
195
+ parser = argparse.ArgumentParser()
196
+ parser.add_argument('-i', '--input', type=json.loads)
197
+ parser.add_argument('-p', '--processes')
198
+ parser.add_argument('-v', '--verbose')
199
+ args = parser.parse_args()
200
+
201
+ verbose = True if args.verbose == 'True' else False
202
+
203
+ tiling = Tiler(print, **args.input, processes=int(args.processes), verbose=verbose)
204
+ tiling.execute()
205
+
206
+ sys.exit(app.exec_())
@@ -0,0 +1,54 @@
1
+ from random import random
2
+ import time
3
+ from multiprocessing.pool import Pool
4
+ from numpy import mean
5
+
6
+ from common import *
7
+
8
+
9
+ class OperationCancelledException(Exception):
10
+ pass
11
+
12
+
13
+ def tool_name(callback, in_line, in_cost_raster, line_radius, process_segments, out_center_line):
14
+ execute_multiprocessing()
15
+ callback('tool_template tool done.')
16
+
17
+
18
+ # task executed in a worker process
19
+ def worker(task_data):
20
+ # report a message
21
+ value = mean(task_data)
22
+ print(f'Task {len(task_data)} with {value} executed', flush=True)
23
+
24
+ # block for a moment
25
+ time.sleep(value * 10)
26
+
27
+ # return the generated value
28
+ return value
29
+
30
+
31
+ # protect the entry point
32
+ def execute_multiprocessing():
33
+ # create and configure the process pool
34
+ data = [[random() for n in range(100)] for i in range(300)]
35
+ try:
36
+ total_steps = 300
37
+ with Pool() as pool:
38
+ step = 0
39
+ # execute tasks in order, process results out of order
40
+ for result in pool.imap_unordered(worker, data):
41
+ print(f'Got result: {result}', flush=True)
42
+ step += 1
43
+ print(step)
44
+ print('%{}'.format(step / total_steps * 100))
45
+
46
+ except OperationCancelledException:
47
+ print("Operation cancelled")
48
+
49
+
50
+ if __name__ == '__main__':
51
+ in_args, in_verbose = check_arguments()
52
+ start_time = time.time()
53
+ tool_name(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
54
+ print('Elapsed time: {}'.format(time.time() - start_time))