-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
150 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
""" | ||
Generates search path for hotspots. | ||
""" | ||
|
||
import math | ||
|
||
from . import plot_circular_path | ||
from .common.modules import position_global_relative_altitude | ||
|
||
|
||
MINIMUM_POINTS = 3 | ||
|
||
|
||
def generate_search_path( | ||
center: position_global_relative_altitude.PositionGlobalRelativeAltitude, | ||
search_radius: float, | ||
search_area_dimensions: "tuple[float, float]", | ||
) -> "tuple[bool, list[position_global_relative_altitude.PositionGlobalRelativeAltitude] | None]": | ||
""" | ||
Generates list of spline waypoints representing concentric rings for drone search path. | ||
center: waypoint for center of circle. | ||
search_radius: drone search radius. | ||
search_area_dimensions: search area width, height | ||
Returns: Success, list of waypoints. | ||
""" | ||
camera_horizontal_size, camera_vertical_size = search_area_dimensions | ||
|
||
if camera_horizontal_size <= 0 or camera_vertical_size <= 0: | ||
print(f"ERROR: Camera dimensions must be greater than 0: {search_area_dimensions}") | ||
return False, None | ||
|
||
if search_radius < 0: | ||
print(f"ERROR: Search radius must be greater than or equal to 0: {search_radius}") | ||
return False, None | ||
|
||
current_radius = camera_horizontal_size / 2 | ||
|
||
all_waypoints = [] | ||
|
||
while current_radius <= search_radius: | ||
circumference = 2 * math.pi * current_radius | ||
num_points = max(MINIMUM_POINTS, int(circumference / camera_vertical_size)) | ||
|
||
result, waypoints = plot_circular_path.generate_circular_path( | ||
center, current_radius, num_points | ||
) | ||
if not result or waypoints is None: | ||
return False, None | ||
all_waypoints.extend(waypoints) | ||
|
||
current_radius += camera_horizontal_size | ||
|
||
return True, all_waypoints |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
""" | ||
Hotspot search path generation unit tests. | ||
""" | ||
|
||
import math | ||
|
||
from modules import generate_hotspot_search_path | ||
from modules.common.modules import position_global_relative_altitude | ||
|
||
|
||
class TestGenerateSearchPath: | ||
""" | ||
Test suite for generate_search_path. | ||
""" | ||
|
||
def test_generate_search_path(self) -> None: | ||
""" | ||
Test successful generation of search path. | ||
""" | ||
result, center = position_global_relative_altitude.PositionGlobalRelativeAltitude.create( | ||
0.0, 0.0, 100.0 | ||
) | ||
search_radius = 100.0 | ||
search_area_dimensions = (20.0, 10.0) | ||
|
||
result, waypoints = generate_hotspot_search_path.generate_search_path( | ||
center, search_radius, search_area_dimensions | ||
) | ||
|
||
assert result | ||
assert waypoints | ||
|
||
camera_width, camera_height = search_area_dimensions | ||
current_radius = camera_width / 2 | ||
waypoint_index = 0 | ||
|
||
while current_radius <= search_radius: | ||
circumference = 2 * math.pi * current_radius | ||
num_points = max(3, int(circumference / camera_height)) | ||
|
||
assert len(waypoints[waypoint_index : waypoint_index + num_points]) == num_points | ||
|
||
waypoint_index += num_points | ||
current_radius += camera_width | ||
|
||
def test_generate_search_path_zero_radius(self) -> None: | ||
""" | ||
Test generate_search_path with a zero search radius. | ||
""" | ||
result, center = position_global_relative_altitude.PositionGlobalRelativeAltitude.create( | ||
0.0, 0.0, 100.0 | ||
) | ||
search_radius = 0.0 | ||
search_area_dimensions = (3.0, 3.0) | ||
|
||
result, waypoints = generate_hotspot_search_path.generate_search_path( | ||
center, search_radius, search_area_dimensions | ||
) | ||
|
||
assert result | ||
assert waypoints == [] | ||
|
||
def test_generate_search_path_negative_radius(self) -> None: | ||
""" | ||
Test generate_search_path with a negative search radius. | ||
""" | ||
result, center = position_global_relative_altitude.PositionGlobalRelativeAltitude.create( | ||
0.0, 0.0, 100.0 | ||
) | ||
search_radius = -10.0 | ||
search_area_dimensions = (3.0, 3.0) | ||
|
||
result, waypoints = generate_hotspot_search_path.generate_search_path( | ||
center, search_radius, search_area_dimensions | ||
) | ||
|
||
assert result is False | ||
assert waypoints is None | ||
|
||
def test_generate_search_path_invalid_dimensions(self) -> None: | ||
""" | ||
Test generate_search_path with invalid search area dimensions. | ||
""" | ||
result, center = position_global_relative_altitude.PositionGlobalRelativeAltitude.create( | ||
0.0, 0.0, 100.0 | ||
) | ||
search_radius = 10.0 | ||
search_area_dimensions = (-3, 3.0) | ||
|
||
result, waypoints = generate_hotspot_search_path.generate_search_path( | ||
center, search_radius, search_area_dimensions | ||
) | ||
|
||
assert result is False | ||
assert waypoints is None |