BERATools 0.5.2__tar.gz → 0.5.4__tar.gz

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 (74) hide show
  1. {beratools-0.5.2 → beratools-0.5.4}/PKG-INFO +13 -13
  2. {beratools-0.5.2 → beratools-0.5.4}/README.md +9 -10
  3. {beratools-0.5.2 → beratools-0.5.4}/beratools/__init__.py +2 -2
  4. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_astar.py +151 -7
  5. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_canopy_footprint_absolute.py +1 -1
  6. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_centerline.py +467 -129
  7. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_check_seed_line.py +112 -0
  8. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_common.py +671 -5
  9. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_cost.py +137 -1
  10. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_geometry.py +11 -0
  11. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_line_grouping.py +19 -3
  12. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_merge_lines.py +1 -1
  13. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_seed_line_correction.py +1 -1
  14. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_vertex_optimization.py +1 -1
  15. beratools-0.5.4/beratools/core/alt_spatial_common.py +149 -0
  16. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/constants.py +1 -1
  17. beratools-0.5.4/beratools/core/logger.py +376 -0
  18. beratools-0.5.4/beratools/core/tool_base.py +217 -0
  19. beratools-0.5.4/beratools/external/polygon_centerline/_src.py +2598 -0
  20. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/beratools.json +7 -7
  21. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/bt_data.py +2 -2
  22. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/bt_gui_main.py +1 -1
  23. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/main.py +1 -1
  24. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/tool_widgets.py +2 -2
  25. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/canopy_footprint_absolute.py +3 -4
  26. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/centerline.py +140 -17
  27. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/check_seed_line.py +11 -5
  28. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/common.py +1 -1
  29. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/ground_footprint.py +3 -5
  30. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/tool_template.py +1 -1
  31. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/vertex_optimization.py +3 -6
  32. {beratools-0.5.2 → beratools-0.5.4}/beratools/utility/spatial_common.py +1 -1
  33. {beratools-0.5.2 → beratools-0.5.4}/pyproject.toml +2 -1
  34. beratools-0.5.2/beratools/core/alt_spatial_common.py +0 -108
  35. beratools-0.5.2/beratools/core/logger.py +0 -93
  36. beratools-0.5.2/beratools/core/tool_base.py +0 -140
  37. beratools-0.5.2/beratools/external/polygon_centerline/_src.py +0 -1058
  38. {beratools-0.5.2 → beratools-0.5.4}/.gitignore +0 -0
  39. {beratools-0.5.2 → beratools-0.5.4}/LICENSE +0 -0
  40. {beratools-0.5.2 → beratools-0.5.4}/beratools/cli/__init__.py +0 -0
  41. {beratools-0.5.2 → beratools-0.5.4}/beratools/cli/entry.py +0 -0
  42. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/__init__.py +0 -0
  43. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_check_seed_line_validate.py +0 -0
  44. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_dijkstra.py +0 -0
  45. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_split_with_lines.py +0 -0
  46. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/algo_vertex_preclean.py +0 -0
  47. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/canopy_threshold_relative.py +0 -0
  48. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/line_footprint_functions.py +0 -0
  49. {beratools-0.5.2 → beratools-0.5.4}/beratools/core/tool_geo_simplify.py +0 -0
  50. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/__init__.py +0 -0
  51. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/geo_simplify/geo-simplify-linux-x64 +0 -0
  52. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/geo_simplify/geo-simplify-win-x64.exe +0 -0
  53. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/polygon_centerline/LICENSE.md +0 -0
  54. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/polygon_centerline/UPSTREAM.md +0 -0
  55. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/polygon_centerline/__init__.py +0 -0
  56. {beratools-0.5.2 → beratools-0.5.4}/beratools/external/polygon_centerline/exceptions.py +0 -0
  57. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/BERALogo.ico +0 -0
  58. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/BERALogo.png +0 -0
  59. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/BERA_GUI_Main.png +0 -0
  60. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/BERA_Splash.gif +0 -0
  61. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/BERA_WizardImage.png +0 -0
  62. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/closed.gif +0 -0
  63. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/closed.png +0 -0
  64. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/gui.json +0 -0
  65. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/open.gif +0 -0
  66. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/open.png +0 -0
  67. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/tool.gif +0 -0
  68. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/assets/tool.png +0 -0
  69. {beratools-0.5.2 → beratools-0.5.4}/beratools/gui/geometry_types.py +0 -0
  70. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/__init__.py +0 -0
  71. {beratools-0.5.2 → beratools-0.5.4}/beratools/tools/line_footprint_relative.py +0 -0
  72. {beratools-0.5.2 → beratools-0.5.4}/beratools/utility/env_checks.py +0 -0
  73. {beratools-0.5.2 → beratools-0.5.4}/beratools/utility/tool_args.py +0 -0
  74. {beratools-0.5.2 → beratools-0.5.4}/beratools/utility/unit_conversion.py +0 -0
@@ -1,8 +1,8 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: BERATools
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Summary: An advanced forest line feature analysis platform
5
- Project-URL: Homepage, https://github.com/appliedgrg/beratools
5
+ Project-URL: Homepage, https://github.com/BERATool/beratools
6
6
  Author-email: AppliedGRG <appliedgrg@gmail.com>, Richard Zeng <richardqzeng@gmail.com>
7
7
  License: GPL-3.0-or-later
8
8
  License-File: LICENSE
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.14
17
17
  Requires-Python: <3.15,>=3.12
18
18
  Requires-Dist: gdal<4,>=3.12; platform_system != 'Windows'
19
19
  Requires-Dist: geopandas
20
+ Requires-Dist: igraph
20
21
  Requires-Dist: networkit
21
22
  Requires-Dist: numpy<2.4,>=1.26
22
23
  Requires-Dist: pandarallel
@@ -55,8 +56,8 @@ BERA Tools is successor of [Forest Line Mapper](https://github.com/appliedgrg/fl
55
56
 
56
57
  <div align="center">
57
58
 
58
- [![Python Integration Tests](https://img.shields.io/github/actions/workflow/status/appliedgrg/beratools/python-integration-tests.yml?branch=main)](https://github.com/appliedgrg/beratools/actions/workflows/python-integration-tests.yml)
59
- [![GitHub Pages](https://img.shields.io/github/deployments/appliedgrg/beratools/github-pages?label=docs)](https://appliedgrg.github.io/beratools/)
59
+ [![Python Integration Tests](https://img.shields.io/github/actions/workflow/status/BERATool/beratools/python-integration-tests.yml?branch=main)](https://github.com/BERATool/beratools/actions/workflows/python-integration-tests.yml)
60
+ [![GitHub Pages](https://img.shields.io/github/deployments/BERATool/beratools/github-pages?label=docs)](https://beratool.github.io/beratools/)
60
61
  [![Conda Version](https://img.shields.io/conda/v/AppliedGRG/beratools)](https://anaconda.org/AppliedGRG/beratools)
61
62
  [![PyPI](https://img.shields.io/pypi/v/BERATools)](https://pypi.org/project/BERATools/)
62
63
  [![Python Version](https://img.shields.io/badge/python-3.12--3.14-blue)](https://www.python.org/downloads/)
@@ -64,7 +65,7 @@ BERA Tools is successor of [Forest Line Mapper](https://github.com/appliedgrg/fl
64
65
 
65
66
  </div>
66
67
 
67
- ## [Quick Start](https://appliedgrg.github.io/beratools)
68
+ ## [Quick Start](https://beratool.github.io/beratools/)
68
69
 
69
70
  Here are the ways to install BERA Tools:
70
71
 
@@ -73,15 +74,14 @@ Here are the ways to install BERA Tools:
73
74
 
74
75
  ### Windows Installer
75
76
 
76
- Windows installer is provided with releases. Check the [latest release](https://github.com/appliedgrg/beratools/releases/latest). Official Windows installers are signed under the BERA Tools [Code signing policy](CODE_SIGNING_POLICY.md).
77
+ Windows installer is provided with releases. Check the [latest release](https://github.com/BERATool/beratools/releases/latest). Official Windows installers are signed under the BERA Tools [Code signing policy](CODE_SIGNING_POLICY.md).
77
78
 
78
79
  ### Install with Anaconda
79
80
 
80
81
  Install with Anaconda works on Windows, macOS, and Linux.
81
82
 
82
83
  - Install Miniconda. Download Miniconda from [Miniconda](https://docs.anaconda.com/miniconda/) and install on your machine.
83
- - Download and save the file [environment.yml](https://raw.githubusercontent.com/appliedgrg/beratools/main/environment.yml
84
- ).
84
+ - Download and save the file [environment.yml](https://raw.githubusercontent.com/BERATool/beratools/main/environment.yml).
85
85
  - Launch **Anaconda Prompt** and **Change directory** to where environment.yml is saved.
86
86
  - Run the command to install BERA Tools.
87
87
 
@@ -99,13 +99,13 @@ Install with Anaconda works on Windows, macOS, and Linux.
99
99
 
100
100
  ![BERA Tools Main GUI](beratools/gui/assets/BERA_GUI_Main.png)
101
101
 
102
- - [Download latest example data](https://github.com/appliedgrg/beratools/releases/latest/download/test_data.zip) to try with BERA Tools.
102
+ - [Download latest example data](https://github.com/BERATool/beratools/releases/latest/download/test_data.zip) to try with BERA Tools.
103
103
 
104
- For more information about installation, check the [BERA Tools Installation](https://appliedgrg.github.io/beratools/user/installation/).
104
+ For more information about installation, check the [BERA Tools Installation](https://beratool.github.io/beratools/user/installation/).
105
105
 
106
106
  ## BERA Tools Guide
107
107
 
108
- Check the online [BERA Tools Guide](https://appliedgrg.github.io/beratools/) for user, developer and technical guides.
108
+ Check the online [BERA Tools Guide](https://beratool.github.io/beratools/) for user, developer and technical guides.
109
109
 
110
110
  ## Sponsors
111
111
 
@@ -126,7 +126,7 @@ Check the online [BERA Tools Guide](https://appliedgrg.github.io/beratools/) for
126
126
 
127
127
  <table>
128
128
  <tr>
129
- <td><img src="https://github.com/appliedgrg/beratools/raw/main/docs/files/icons/bera_logo.png" alt="Logos" width="80"></td>
129
+ <td><img src="https://github.com/BERATool/beratools/raw/main/docs/files/icons/bera_logo.png" alt="Logos" width="80"></td>
130
130
  <td>
131
131
  <p>
132
132
  This tool is part of the <strong><a href="http://www.beraproject.org/">Boreal Ecosystem Recovery & Assessment (BERA)</a></strong>.
@@ -4,8 +4,8 @@ BERA Tools is successor of [Forest Line Mapper](https://github.com/appliedgrg/fl
4
4
 
5
5
  <div align="center">
6
6
 
7
- [![Python Integration Tests](https://img.shields.io/github/actions/workflow/status/appliedgrg/beratools/python-integration-tests.yml?branch=main)](https://github.com/appliedgrg/beratools/actions/workflows/python-integration-tests.yml)
8
- [![GitHub Pages](https://img.shields.io/github/deployments/appliedgrg/beratools/github-pages?label=docs)](https://appliedgrg.github.io/beratools/)
7
+ [![Python Integration Tests](https://img.shields.io/github/actions/workflow/status/BERATool/beratools/python-integration-tests.yml?branch=main)](https://github.com/BERATool/beratools/actions/workflows/python-integration-tests.yml)
8
+ [![GitHub Pages](https://img.shields.io/github/deployments/BERATool/beratools/github-pages?label=docs)](https://beratool.github.io/beratools/)
9
9
  [![Conda Version](https://img.shields.io/conda/v/AppliedGRG/beratools)](https://anaconda.org/AppliedGRG/beratools)
10
10
  [![PyPI](https://img.shields.io/pypi/v/BERATools)](https://pypi.org/project/BERATools/)
11
11
  [![Python Version](https://img.shields.io/badge/python-3.12--3.14-blue)](https://www.python.org/downloads/)
@@ -13,7 +13,7 @@ BERA Tools is successor of [Forest Line Mapper](https://github.com/appliedgrg/fl
13
13
 
14
14
  </div>
15
15
 
16
- ## [Quick Start](https://appliedgrg.github.io/beratools)
16
+ ## [Quick Start](https://beratool.github.io/beratools/)
17
17
 
18
18
  Here are the ways to install BERA Tools:
19
19
 
@@ -22,15 +22,14 @@ Here are the ways to install BERA Tools:
22
22
 
23
23
  ### Windows Installer
24
24
 
25
- Windows installer is provided with releases. Check the [latest release](https://github.com/appliedgrg/beratools/releases/latest). Official Windows installers are signed under the BERA Tools [Code signing policy](CODE_SIGNING_POLICY.md).
25
+ Windows installer is provided with releases. Check the [latest release](https://github.com/BERATool/beratools/releases/latest). Official Windows installers are signed under the BERA Tools [Code signing policy](CODE_SIGNING_POLICY.md).
26
26
 
27
27
  ### Install with Anaconda
28
28
 
29
29
  Install with Anaconda works on Windows, macOS, and Linux.
30
30
 
31
31
  - Install Miniconda. Download Miniconda from [Miniconda](https://docs.anaconda.com/miniconda/) and install on your machine.
32
- - Download and save the file [environment.yml](https://raw.githubusercontent.com/appliedgrg/beratools/main/environment.yml
33
- ).
32
+ - Download and save the file [environment.yml](https://raw.githubusercontent.com/BERATool/beratools/main/environment.yml).
34
33
  - Launch **Anaconda Prompt** and **Change directory** to where environment.yml is saved.
35
34
  - Run the command to install BERA Tools.
36
35
 
@@ -48,13 +47,13 @@ Install with Anaconda works on Windows, macOS, and Linux.
48
47
 
49
48
  ![BERA Tools Main GUI](beratools/gui/assets/BERA_GUI_Main.png)
50
49
 
51
- - [Download latest example data](https://github.com/appliedgrg/beratools/releases/latest/download/test_data.zip) to try with BERA Tools.
50
+ - [Download latest example data](https://github.com/BERATool/beratools/releases/latest/download/test_data.zip) to try with BERA Tools.
52
51
 
53
- For more information about installation, check the [BERA Tools Installation](https://appliedgrg.github.io/beratools/user/installation/).
52
+ For more information about installation, check the [BERA Tools Installation](https://beratool.github.io/beratools/user/installation/).
54
53
 
55
54
  ## BERA Tools Guide
56
55
 
57
- Check the online [BERA Tools Guide](https://appliedgrg.github.io/beratools/) for user, developer and technical guides.
56
+ Check the online [BERA Tools Guide](https://beratool.github.io/beratools/) for user, developer and technical guides.
58
57
 
59
58
  ## Sponsors
60
59
 
@@ -75,7 +74,7 @@ Check the online [BERA Tools Guide](https://appliedgrg.github.io/beratools/) for
75
74
 
76
75
  <table>
77
76
  <tr>
78
- <td><img src="https://github.com/appliedgrg/beratools/raw/main/docs/files/icons/bera_logo.png" alt="Logos" width="80"></td>
77
+ <td><img src="https://github.com/BERATool/beratools/raw/main/docs/files/icons/bera_logo.png" alt="Logos" width="80"></td>
79
78
  <td>
80
79
  <p>
81
80
  This tool is part of the <strong><a href="http://www.beraproject.org/">Boreal Ecosystem Recovery & Assessment (BERA)</a></strong>.
@@ -1,8 +1,8 @@
1
1
  __author__ = """Applied Geospatial Research Group"""
2
2
  __email__ = 'appliedgrg@gmail.com'
3
- __version__ = '0.5.2'
3
+ __version__ = '0.5.3'
4
4
  __license__ = "GPL-3.0-or-later"
5
5
  __copyright__ = "Copyright (c) AppliedGRG"
6
6
  __status__ = "Pre-Alpha"
7
- __url__ = "https://github.com/appliedgrg/beratools"
7
+ __url__ = "https://github.com/BERATool/beratools"
8
8
  __all__ = ["tools", "gui"]
@@ -10,9 +10,18 @@ from typing import Iterable
10
10
 
11
11
  import numpy as np
12
12
  import rasterio
13
+ import logging
14
+
13
15
  from rasterio.features import geometry_mask
14
16
  from scipy import ndimage
15
17
  from shapely.geometry import LineString
18
+ import shapely.ops as sh_ops
19
+ import shapely.geometry as sh_geom
20
+ import beratools.core.algo_common as algo_common
21
+
22
+ LOGGER_NAME = "centerline"
23
+ logger = logging.getLogger(LOGGER_NAME)
24
+
16
25
 
17
26
 
18
27
  SQRT2 = math.sqrt(2.0)
@@ -39,21 +48,139 @@ class AStarAccumulation:
39
48
  g_scores: np.ndarray
40
49
  closed: np.ndarray
41
50
 
51
+ def nearest_valid_cell(cost, start_rc, max_radius=20):
52
+ """find the nearest valid cell if lcp start/end point land on nodata cell."""
53
+ r0, c0 = start_rc
54
+ if np.isfinite(cost[r0, c0]):
55
+ return start_rc
56
+ rows, cols = cost.shape
57
+ for radius in range(1, max_radius + 1):
58
+ rmin = max(0, r0 - radius)
59
+ rmax = min(rows, r0 + radius + 1)
60
+ cmin = max(0, c0 - radius)
61
+ cmax = min(cols, c0 + radius + 1)
62
+ best_cell = None
63
+ best_dist = float("inf")
64
+ for r in range(rmin, rmax):
65
+ for c in range(cmin, cmax):
66
+ if not np.isfinite(cost[r, c]):
67
+ continue
68
+ dist = (r - r0) ** 2 + (c - c0) ** 2
69
+ if dist < best_dist:
70
+ best_dist = dist
71
+ best_cell = (r, c)
72
+ if best_cell is not None:
73
+ return best_cell
74
+ return None
42
75
 
43
- def find_least_cost_path_astar_closest_line(cost_arr, meta: dict, input_line: LineString) -> LineString | None:
76
+ def nearest_valid_location_on_line(
77
+ cost_arr,
78
+ transform,
79
+ line,
80
+ from_start=True,
81
+ step=1.0,
82
+ max_search=20.0,
83
+ ):
84
+ length = line.length
85
+
86
+ if from_start:
87
+ distances = np.arange(0, min(max_search, length), step)
88
+ else:
89
+ distances = np.arange(
90
+ length,
91
+ max(length - max_search, 0),
92
+ -step,
93
+ )
94
+
95
+ for d in distances:
96
+ pt = line.interpolate(d)
97
+
98
+ r, c = rasterio.transform.rowcol(
99
+ transform,
100
+ pt.x,
101
+ pt.y,
102
+ )
103
+
104
+ if np.isfinite(cost_arr[r, c]):
105
+ return pt, (r, c)
106
+
107
+ return None, None
108
+
109
+ def find_least_cost_path_astar_closest_line(cost_arr, meta: dict, input_line: LineString, cid=None) -> LineString | None:
44
110
  """Find an 8-neighbor A* LCP, tie-broken toward the seed-line direction."""
45
111
 
46
112
  if input_line is None or input_line.is_empty or len(input_line.coords) < 2:
113
+ logger.info(cid+f"Input line is empty or too short: {input_line}")
47
114
  return None
48
115
 
116
+ x1, y1 = input_line.coords[0]
117
+ x2, y2 = input_line.coords[-1]
49
118
  costs, walkable = _prepare_lcp_costs(cost_arr, meta.get("nodata"))
50
119
  rows, cols = costs.shape
51
120
  transformer = rasterio.transform.AffineTransformer(meta["transform"])
52
- start_xy = input_line.coords[0]
53
- end_xy = input_line.coords[-1]
54
- start = _clamp_row_col(transformer.rowcol(start_xy[0], start_xy[1]), rows, cols)
55
- end = _clamp_row_col(transformer.rowcol(end_xy[0], end_xy[1]), rows, cols)
121
+ start_rc = rasterio.transform.rowcol(meta["transform"], x1, y1)
122
+ end_rc = rasterio.transform.rowcol(meta["transform"], x2, y2)
123
+ if not walkable[start_rc]:
124
+ start_xy_pt,start_rc_fixed=nearest_valid_location_on_line(cost_arr, meta["transform"], input_line,
125
+ from_start=True,step=meta["transform"].a,
126
+ max_search=10.0)
127
+ if start_rc_fixed is None:
128
+ start_rc_fixed = nearest_valid_cell(cost_arr, start_rc)
129
+ if start_rc_fixed is None:
130
+ logger.info(cid+f"Start point is not traversable: {start_rc}")
131
+ return None
132
+ else:
133
+ sx,sy=rasterio.transform.xy(meta["transform"], start_rc_fixed[0], start_rc_fixed[-1])
134
+ start_xy_pt =sh_geom.Point(sx,sy)
135
+
136
+ ds=input_line.project(start_xy_pt)
137
+ start_connector=sh_ops.substring(input_line,0,ds)
138
+ logger.warning(
139
+ cid +
140
+ f" start_connector_type={type(start_connector).__name__ if start_connector is not None else None}"
141
+ )
142
+ start_xy=start_xy_pt.coords[0]
143
+ logger.warning(
144
+ cid +
145
+ f" moved start {start_rc}->{start_rc_fixed}"
146
+ )
147
+ else:
148
+ start_rc_fixed = start_rc
149
+ start_connector=None
150
+ start_xy = (x1, y1)
151
+ if not walkable[end_rc]:
152
+ end_xy_pt,end_rc_fixed=nearest_valid_location_on_line(cost_arr, meta["transform"], input_line,
153
+ from_start=False,step=meta["transform"].a,
154
+ max_search=10.0)
155
+ if end_rc_fixed is None:
156
+ end_rc_fixed= nearest_valid_cell(cost_arr, end_rc)
157
+ if end_rc_fixed is None:
158
+ logger.info(cid+f"End point is not traversable: {end_rc}")
159
+ return None
160
+ else:
161
+ ex,ey=rasterio.transform.xy(meta["transform"], end_rc_fixed[0], end_rc_fixed[-1])
162
+ end_xy_pt =sh_geom.Point(ex,ey)
163
+ de = input_line.project(end_xy_pt)
164
+ end_connector = sh_ops.substring(input_line, de, input_line.length)
165
+ logger.warning(
166
+ cid +
167
+ f" end_connector_type={type(end_connector).__name__ if end_connector is not None else None}"
168
+ )
169
+ end_xy = end_xy_pt.coords[0]
170
+ logger.warning(
171
+ cid +
172
+ f" moved end {end_rc}->{end_rc_fixed}"
173
+ )
174
+ else:
175
+ end_rc_fixed = end_rc
176
+ end_xy = (x2, y2)
177
+ end_connector = None
178
+
179
+ start = _clamp_row_col(start_rc_fixed, rows, cols)
180
+ end = _clamp_row_col(end_rc_fixed, rows, cols)
56
181
  if not walkable[start] or not walkable[end]:
182
+ logger.info(cid+
183
+ f"Start or end point is not traversable: {start_rc_fixed} or {end_rc_fixed}")
57
184
  return None
58
185
 
59
186
  min_cost = float(costs[walkable].min()) if np.any(walkable) else 0.0
@@ -73,7 +200,19 @@ def find_least_cost_path_astar_closest_line(cost_arr, meta: dict, input_line: Li
73
200
  if current in closed:
74
201
  continue
75
202
  if current == end:
76
- return _path_to_linestring(_reconstruct_path(came_from, end), transformer, start_xy, end_xy)
203
+ lcp = _path_to_linestring(_reconstruct_path(came_from, end), transformer, start_xy, end_xy)
204
+ segments = []
205
+ if start_connector is not None:
206
+ segments.append(start_connector)
207
+
208
+ segments.append(lcp)
209
+
210
+ if end_connector is not None:
211
+ segments.append(end_connector)
212
+ if len(segments) == 1:
213
+ return segments[0]
214
+ return algo_common._safe_linemerge(sh_geom.MultiLineString(segments))
215
+
77
216
  closed.add(current)
78
217
 
79
218
  for neighbor in _neighbors(current, rows, cols, walkable):
@@ -94,7 +233,7 @@ def find_least_cost_path_astar_closest_line(cost_arr, meta: dict, input_line: Li
94
233
  heap,
95
234
  _lcp_queue_entry(neighbor, end, start, new_g, new_tie, min_cost, next(sequence)),
96
235
  )
97
-
236
+ logger.info(cid+f'No path found between {start_rc_fixed} and {end_rc_fixed} using A* LCP.')
98
237
  return None
99
238
 
100
239
 
@@ -120,6 +259,11 @@ def astar_accumulation_corridor_raster(
120
259
  end_xy = lc_path.coords[-1]
121
260
  source = _clamp_row_col(transformer.rowcol(*start_xy), rows, cols)
122
261
  destination = _clamp_row_col(transformer.rowcol(*end_xy), rows, cols)
262
+ if not np.isfinite(cost[source]):
263
+ _, source = nearest_valid_location_on_line(cost_arr, meta["transform"], lc_path, from_start=True,step=meta['transform'].a)
264
+
265
+ if not np.isfinite(cost[destination]):
266
+ _, destination = nearest_valid_location_on_line(cost_arr, meta["transform"], lc_path, from_start=False,step=meta['transform'].a)
123
267
  sampling = _raster_sampling(transform)
124
268
 
125
269
  forward = _astar_mcp_geometric_accumulation(
@@ -8,7 +8,7 @@ Author: Richard Zeng, Maverick Fong
8
8
 
9
9
  Description:
10
10
  This script is part of the BERA Tools.
11
- Webpage: https://github.com/appliedgrg/beratools
11
+ Webpage: https://github.com/BERATool/beratools
12
12
 
13
13
  The purpose of this script is to provide main interface for adaptive relative canopy footprint tool.
14
14
  The tool is used to generate the canopy footprint of a line based on adaptive relative threshold.