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
beratools/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ from beratools.core import *
2
+ from beratools.tools import *
3
+ from beratools.gui import *
4
+ from beratools.third_party import *
5
+ from beratools.core import logger
6
+
7
+ __author__ = """AppliedGRG"""
8
+ __email__ = 'appliedgrg@gmail.com'
9
+ __version__ = '0.2.0'
File without changes
@@ -0,0 +1,351 @@
1
+ import numpy as np
2
+ from rasterio import features
3
+ import shapely
4
+ from shapely.geometry import shape
5
+ from shapely.ops import unary_union, substring, linemerge, nearest_points, split
6
+ from shapely.geometry import Point, MultiPoint, Polygon, MultiPolygon, LineString, MultiLineString
7
+ # from beratools.third_party.label_centerlines import get_centerline
8
+ from label_centerlines import get_centerline
9
+
10
+ from beratools.core.tool_base import *
11
+ from beratools.core.constants import *
12
+ from beratools.tools.common import generate_perpendicular_line_precise
13
+
14
+
15
+ def centerline_is_valid(centerline, input_line):
16
+ """
17
+ Check if centerline is valid
18
+ Parameters
19
+ ----------
20
+ centerline :
21
+ input_line : shapely LineString
22
+ This can be input seed line or least cost path. Only two end points are used.
23
+
24
+ Returns
25
+ -------
26
+
27
+ """
28
+ if not centerline:
29
+ return False
30
+
31
+ # centerline length less the half of least cost path
32
+ if (centerline.length < input_line.length / 2 or
33
+ centerline.distance(Point(input_line.coords[0])) > BT_EPSILON or
34
+ centerline.distance(Point(input_line.coords[-1])) > BT_EPSILON):
35
+ return False
36
+
37
+ return True
38
+
39
+
40
+ def snap_end_to_end(in_line, line_reference):
41
+ if type(in_line) is MultiLineString:
42
+ in_line = linemerge(in_line)
43
+ if type(in_line) is MultiLineString:
44
+ print(f'algo_centerline: MultiLineString found {in_line.centroid}, pass.')
45
+ return None
46
+
47
+ pts = list(in_line.coords)
48
+ if len(pts) < 2:
49
+ print('snap_end_to_end: input line invalid.')
50
+ return in_line
51
+
52
+ line_start = Point(pts[0])
53
+ line_end = Point(pts[-1])
54
+ ref_ends = MultiPoint([line_reference.coords[0], line_reference.coords[-1]])
55
+
56
+ _, snap_start = nearest_points(line_start, ref_ends)
57
+ _, snap_end = nearest_points(line_end, ref_ends)
58
+
59
+ if in_line.has_z:
60
+ snap_start = shapely.force_3d(snap_start)
61
+ snap_end = shapely.force_3d(snap_end)
62
+ else:
63
+ snap_start = shapely.force_2d(snap_start)
64
+ snap_end = shapely.force_2d(snap_end)
65
+
66
+ pts[0] = snap_start.coords[0]
67
+ pts[-1] = snap_end.coords[0]
68
+
69
+ return LineString(pts)
70
+
71
+
72
+ def find_centerline(poly, input_line):
73
+ """
74
+ Parameters
75
+ ----------
76
+ poly : Polygon
77
+ input_line : LineString
78
+ Least cost path or seed line
79
+
80
+ Returns
81
+ -------
82
+
83
+ """
84
+ default_return = input_line, CenterlineStatus.FAILED
85
+ if not poly:
86
+ print('find_centerline: No polygon found')
87
+ return default_return
88
+
89
+ poly = shapely.segmentize(poly, max_segment_length=CL_SEGMENTIZE_LENGTH)
90
+
91
+ poly = poly.buffer(CL_POLYGON_BUFFER) # buffer polygon to reduce MultiPolygons
92
+ if type(poly) is MultiPolygon:
93
+ print('MultiPolygon encountered, skip.')
94
+ return default_return
95
+
96
+ exterior_pts = list(poly.exterior.coords)
97
+
98
+ if CL_DELETE_HOLES:
99
+ poly = Polygon(exterior_pts)
100
+ if CL_SIMPLIFY_POLYGON:
101
+ poly = poly.simplify(CL_SIMPLIFY_LENGTH)
102
+
103
+ line_coords = list(input_line.coords)
104
+
105
+ # TODO add more code to filter voronoi vertices
106
+ src_geom = Point(line_coords[0]).buffer(CL_BUFFER_CLIP*3).intersection(poly)
107
+ dst_geom = Point(line_coords[-1]).buffer(CL_BUFFER_CLIP*3).intersection(poly)
108
+ src_geom = None
109
+ dst_geom = None
110
+
111
+ try:
112
+ centerline = get_centerline(poly, segmentize_maxlen=1, max_points=3000,
113
+ simplification=0.05, smooth_sigma=CL_SMOOTH_SIGMA, max_paths=1,
114
+ src_geom=src_geom, dst_geom=dst_geom)
115
+ except Exception as e:
116
+ print(e)
117
+ return default_return
118
+
119
+ if not centerline:
120
+ return default_return
121
+
122
+ if type(centerline) is MultiLineString:
123
+ if len(centerline.geoms) > 1:
124
+ print(" Multiple centerline segments detected, no further processing.")
125
+ return centerline, CenterlineStatus.SUCCESS # TODO: inspect
126
+ elif len(centerline.geoms) == 1:
127
+ centerline = centerline.geoms[0]
128
+ else:
129
+ return default_return
130
+
131
+ cl_coords = list(centerline.coords)
132
+
133
+ # trim centerline at two ends
134
+ head_buffer = Point(cl_coords[0]).buffer(CL_BUFFER_CLIP)
135
+ centerline = centerline.difference(head_buffer)
136
+
137
+ end_buffer = Point(cl_coords[-1]).buffer(CL_BUFFER_CLIP)
138
+ centerline = centerline.difference(end_buffer)
139
+
140
+ if not centerline:
141
+ print('No centerline detected, use input line instead.')
142
+ return default_return
143
+ try:
144
+ if centerline.is_empty:
145
+ print('Empty centerline detected, use input line instead.')
146
+ return default_return
147
+ except Exception as e:
148
+ print(e)
149
+
150
+ centerline = snap_end_to_end(centerline, input_line)
151
+
152
+ # Check if centerline is valid. If not, regenerate by splitting polygon into two halves.
153
+ if not centerline_is_valid(centerline, input_line):
154
+ try:
155
+ print(f'Regenerating line ...')
156
+ centerline = regenerate_centerline(poly, input_line)
157
+ return centerline, CenterlineStatus.REGENERATE_SUCCESS
158
+ except Exception as e:
159
+ print('find_centerline: Exception occurred. \n {}'.format(e))
160
+ return input_line, CenterlineStatus.REGENERATE_FAILED
161
+
162
+ return centerline, CenterlineStatus.SUCCESS
163
+
164
+
165
+ # def find_route(array, start, end, fully_connected, geometric):
166
+ # route_list, cost_list = route_through_array(array, start, end, fully_connected, geometric)
167
+ # return route_list, cost_list
168
+
169
+
170
+ def find_corridor_polygon(corridor_thresh, in_transform, line_gpd):
171
+ # Threshold corridor raster used for generating centerline
172
+ corridor_thresh_cl = np.ma.where(corridor_thresh == 0.0, 1, 0).data
173
+ corridor_mask = np.where(1 == corridor_thresh_cl, True, False)
174
+ poly_generator = features.shapes(corridor_thresh_cl, mask=corridor_mask, transform=in_transform)
175
+ corridor_polygon = []
176
+
177
+ try:
178
+ for poly, value in poly_generator:
179
+ if shape(poly).area > 1:
180
+ corridor_polygon.append(shape(poly))
181
+ except Exception as e:
182
+ print(e)
183
+
184
+ if corridor_polygon:
185
+ corridor_polygon = (unary_union(corridor_polygon))
186
+ if type(corridor_polygon) is MultiPolygon:
187
+ poly_list = shapely.get_parts(corridor_polygon)
188
+ merge_poly = poly_list[0]
189
+ for i in range(1, len(poly_list)):
190
+ if shapely.intersects(merge_poly, poly_list[i]):
191
+ merge_poly = shapely.union(merge_poly, poly_list[i])
192
+ else:
193
+ buffer_dist = poly_list[i].distance(merge_poly) + 0.1
194
+ buffer_poly = poly_list[i].buffer(buffer_dist)
195
+ merge_poly = shapely.union(merge_poly, buffer_poly)
196
+ corridor_polygon = merge_poly
197
+ else:
198
+ corridor_polygon = None
199
+
200
+ # create GeoDataFrame for centerline
201
+ corridor_poly_gpd = gpd.GeoDataFrame.copy(line_gpd)
202
+ corridor_poly_gpd.geometry = [corridor_polygon]
203
+
204
+ return corridor_poly_gpd
205
+
206
+
207
+ def process_single_centerline(row_and_path):
208
+ """
209
+
210
+ Parameters
211
+ ----------
212
+ row_and_path:
213
+ list of row (polygon and props) and least cost path
214
+ first is geopandas row, second is input line, (least cost path)
215
+
216
+ Returns
217
+ -------
218
+
219
+ """
220
+ row = row_and_path[0]
221
+ lc_path = row_and_path[1]
222
+
223
+ poly = row.geometry.iloc[0]
224
+ centerline, status = find_centerline(poly, lc_path)
225
+ row['centerline'] = centerline
226
+
227
+ return row
228
+
229
+
230
+ def find_centerlines(poly_gpd, line_seg, processes):
231
+ centerline = None
232
+ centerline_gpd = []
233
+ rows_and_paths = []
234
+
235
+ try:
236
+ for i in poly_gpd.index:
237
+ row = poly_gpd.loc[[i]]
238
+ poly = row.geometry.iloc[0]
239
+ if 'OLnSEG' in line_seg.columns:
240
+ line_id, Seg_id = row['OLnFID'].iloc[0], row['OLnSEG'].iloc[0]
241
+ lc_path = line_seg.loc[(line_seg.OLnFID == line_id) & (line_seg.OLnSEG == Seg_id)]['geometry'].iloc[0]
242
+ else:
243
+ line_id = row['OLnFID'].iloc[0]
244
+ lc_path = line_seg.loc[(line_seg.OLnFID == line_id)]['geometry'].iloc[0]
245
+
246
+ rows_and_paths.append((row, lc_path))
247
+ except Exception as e:
248
+ print(e)
249
+
250
+ total_steps = len(rows_and_paths)
251
+ step = 0
252
+
253
+ # if PARALLEL_MODE == ParallelMode.MULTIPROCESSING:
254
+ # with Pool(processes=processes) as pool:
255
+ # # execute tasks in order, process results out of order
256
+ # for result in pool.imap_unordered(process_single_centerline, rows_and_paths):
257
+ # centerline_gpd.append(result)
258
+ # step += 1
259
+ # print(' "PROGRESS_LABEL Centerline {} of {}" '.format(step, total_steps), flush=True)
260
+ # print(' %{} '.format(step / total_steps * 100))
261
+ # print('Centerline No. {} done'.format(step))
262
+ # elif PARALLEL_MODE == ParallelMode.SEQUENTIAL:
263
+ # for item in rows_and_paths:
264
+ # row_with_centerline = process_single_centerline(item)
265
+ # centerline_gpd.append(row_with_centerline)
266
+ # step += 1
267
+ # print(' "PROGRESS_LABEL Centerline {} of {}" '.format(step, total_steps), flush=True)
268
+ # print(' %{} '.format(step / total_steps * 100))
269
+ # print('Centerline No. {} done'.format(step))
270
+ centerline_gpd = execute_multiprocessing(process_single_centerline, rows_and_paths,
271
+ 'find_centerlines', processes, 1)
272
+ return pd.concat(centerline_gpd)
273
+
274
+
275
+ def regenerate_centerline(poly, input_line):
276
+ """
277
+ Regenerates centerline when initial
278
+ ----------
279
+ poly : line is not valid
280
+ Parameters
281
+ input_line : shapely LineString
282
+ This can be input seed line or least cost path. Only two end points will be used
283
+
284
+ Returns
285
+ -------
286
+
287
+ """
288
+ line_1 = substring(input_line, start_dist=0.0, end_dist=input_line.length / 2)
289
+ line_2 = substring(input_line, start_dist=input_line.length / 2, end_dist=input_line.length)
290
+
291
+ pts = shapely.force_2d([Point(list(input_line.coords)[0]),
292
+ Point(list(line_1.coords)[-1]),
293
+ Point(list(input_line.coords)[-1])])
294
+ perp = generate_perpendicular_line_precise(pts)
295
+
296
+ # MultiPolygon is rare, but need to be dealt with
297
+ # remove polygon of area less than CL_CLEANUP_POLYGON_BY_AREA
298
+ poly = poly.buffer(CL_POLYGON_BUFFER)
299
+ if type(poly) is MultiPolygon:
300
+ poly_geoms = list(poly.geoms)
301
+ poly_valid = [True] * len(poly_geoms)
302
+ for i, item in enumerate(poly_geoms):
303
+ if item.area < CL_CLEANUP_POLYGON_BY_AREA:
304
+ poly_valid[i] = False
305
+
306
+ poly_geoms = list(compress(poly_geoms, poly_valid))
307
+ if len(poly_geoms) != 1: # still multi polygon
308
+ print('regenerate_centerline: Multi or none polygon found, pass.')
309
+
310
+ poly = Polygon(poly_geoms[0])
311
+
312
+ poly_exterior = Polygon(poly.buffer(CL_POLYGON_BUFFER).exterior)
313
+ poly_split = split(poly_exterior, perp)
314
+
315
+ if len(poly_split.geoms) < 2:
316
+ print('regenerate_centerline: polygon split failed, pass.')
317
+ return None
318
+
319
+ poly_1 = poly_split.geoms[0]
320
+ poly_2 = poly_split.geoms[1]
321
+
322
+ # find polygon and line pairs
323
+ pair_line_1 = line_1
324
+ pair_line_2 = line_2
325
+ if not poly_1.intersects(line_1):
326
+ pair_line_1 = line_2
327
+ pair_line_2 = line_1
328
+ elif poly_1.intersection(line_1).length < line_1.length / 3:
329
+ pair_line_1 = line_2
330
+ pair_line_2 = line_1
331
+
332
+ center_line_1 = find_centerline(poly_1, pair_line_1)
333
+ center_line_2 = find_centerline(poly_2, pair_line_2)
334
+
335
+ center_line_1 = center_line_1[0]
336
+ center_line_2 = center_line_2[0]
337
+
338
+ if not center_line_1 or not center_line_2:
339
+ print('Regenerate line: centerline is None')
340
+ return None
341
+
342
+ try:
343
+ if center_line_1.is_empty or center_line_2.is_empty:
344
+ print('Regenerate line: centerline is empty')
345
+ return None
346
+ except Exception as e:
347
+ print(e)
348
+
349
+ print(f'Centerline is regenerated.')
350
+ return linemerge(MultiLineString([center_line_1, center_line_2]))
351
+
@@ -0,0 +1,86 @@
1
+ import numpy as np
2
+ from enum import Flag, Enum, IntEnum, unique
3
+
4
+
5
+ NADDatum = ['NAD83 Canadian Spatial Reference System', 'North American Datum 1983']
6
+
7
+ BT_DEBUGGING = False
8
+ BT_SHOW_ADVANCED_OPTIONS = False
9
+ HAS_COST_RASTER = False
10
+
11
+ BT_UID = 'BT_UID'
12
+
13
+ BT_EPSILON = np.finfo(float).eps
14
+ BT_NODATA_COST = np.inf
15
+ BT_NODATA = -9999
16
+ BT_MAXIMUM_CPU_CORES = 60 # multiprocessing has limit of 64, consider pathos
17
+ BT_BUFFER_RATIO = 0.0 # overlapping ratio of raster when clipping lines
18
+ BT_LABEL_MIN_WIDTH = 130
19
+
20
+ GROUPING_SEGMENT = True
21
+ LP_SEGMENT_LENGTH = 500
22
+
23
+ FP_CORRIDOR_THRESHOLD = 2.5
24
+ FP_SEGMENTIZE_LENGTH = 2.0
25
+ FP_FIXED_WIDTH_DEFAULT = 5.0
26
+ FP_PERP_LINE_OFFSET = 30.0
27
+
28
+ # centerline
29
+ CL_USE_SKIMAGE_GRAPH = False
30
+ CL_DELETE_HOLES = True
31
+ CL_SIMPLIFY_POLYGON = True
32
+
33
+ CL_BUFFER_CLIP = 10.0
34
+ CL_BUFFER_CENTROID = 3.0
35
+ CL_SNAP_TOLERANCE = 15.0
36
+ CL_SEGMENTIZE_LENGTH = 1.0
37
+ CL_SIMPLIFY_LENGTH = 0.5
38
+ CL_SMOOTH_SIGMA = 0.8
39
+ CL_CLEANUP_POLYGON_BY_AREA = 1.0
40
+ CL_POLYGON_BUFFER = 1e-6
41
+
42
+
43
+ class FootprintParams(float, Enum):
44
+ FP_CORRIDOR_THRESHOLD = 2.5
45
+ FP_SEGMENTIZE_LENGTH = 2.0
46
+ FP_FIXED_WIDTH_DEFAULT = 5.0
47
+ FP_PERP_LINE_OFFSET = 30.0
48
+
49
+
50
+ class CenterlineParams(float, Enum):
51
+ BUFFER_CLIP = 5.0
52
+ BUFFER_CENTROID = 3.0
53
+ SNAP_TOLERANCE = 15.0
54
+ SEGMENTIZE_LENGTH = 1.0
55
+ SIMPLIFY_LENGTH = 0.5
56
+ SMOOTH_SIGMA = 0.8
57
+ CLEANUP_POLYGON_BY_AREA = 1.0
58
+ POLYGON_BUFFER = 1e-6
59
+
60
+
61
+ class CenterlineFlags(Flag):
62
+ USE_SKIMAGE_GRAPH = False
63
+ DELETE_HOLES = True
64
+ SIMPLIFY_POLYGON = True
65
+
66
+
67
+ @unique
68
+ class CenterlineStatus(IntEnum):
69
+ SUCCESS = 1
70
+ FAILED = 2
71
+ REGENERATE_SUCCESS = 3
72
+ REGENERATE_FAILED = 4
73
+
74
+
75
+ @unique
76
+ class ParallelMode(IntEnum):
77
+ SEQUENTIAL = 1
78
+ MULTIPROCESSING = 2
79
+ CONCURRENT = 3
80
+ DASK = 4
81
+ # RAY = 5
82
+
83
+
84
+ PARALLEL_MODE = ParallelMode.MULTIPROCESSING
85
+
86
+