2.8.2 grid mission

master
ken910606 3 weeks ago
parent ed4e4dce10
commit 3cede3aeca

@ -147,11 +147,11 @@ class ToggleSwitch(QWidget):
class ControlStationUI(QMainWindow): class ControlStationUI(QMainWindow):
planning_finished = pyqtSignal(object) planning_finished = pyqtSignal(object)
VERSION = '2.8.0' VERSION = '2.8.2'
FONT_SCALE_MIN = 70 FONT_SCALE_MIN = 70
FONT_SCALE_MAX = 180 FONT_SCALE_MAX = 180
FONT_SCALE_DEFAULT = 100 FONT_SCALE_DEFAULT = 100
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setWindowTitle(f'GCS v{self.VERSION}') self.setWindowTitle(f'GCS v{self.VERSION}')
@ -1596,6 +1596,8 @@ class ControlStationUI(QMainWindow):
group.planned_waypoints = None group.planned_waypoints = None
group.mission_target = None group.mission_target = None
self.drone_map.clear_mission_plan_for_group(group_id) self.drone_map.clear_mission_plan_for_group(group_id)
self.drone_map.clear_grid_sweep_area_for_group(
group_id, restart_selection=(group.mission_type == 'GRID_SWEEP'))
panel = self.group_panels.get(group_id) panel = self.group_panels.get(group_id)
if panel: if panel:
panel.update_status() panel.update_status()
@ -1876,6 +1878,7 @@ class ControlStationUI(QMainWindow):
if group.executor: if group.executor:
group.executor.stop() group.executor.stop()
self.drone_map.clear_mission_plan_for_group(group_id) self.drone_map.clear_mission_plan_for_group(group_id)
self.drone_map.clear_grid_sweep_area_for_group(group_id)
# 只有當操作目標組是 active 組時,才更新 UI # 只有當操作目標組是 active 組時,才更新 UI
if group_id == self.active_group_id: if group_id == self.active_group_id:
@ -1910,6 +1913,7 @@ class ControlStationUI(QMainWindow):
# 移除地圖上的任務計畫 # 移除地圖上的任務計畫
self.drone_map.clear_mission_plan_for_group(group_id) self.drone_map.clear_mission_plan_for_group(group_id)
self.drone_map.clear_grid_sweep_area_for_group(group_id)
# 移除 tab # 移除 tab
for i in range(self.group_tab_widget.count()): for i in range(self.group_tab_widget.count()):
@ -2256,10 +2260,14 @@ class ControlStationUI(QMainWindow):
center_lat, center_lon, _ = center_origin center_lat, center_lon, _ = center_origin
target_lat, target_lon = context['draw_target'] target_lat, target_lon = context['draw_target']
group.mission_target = (float(target_lat), float(target_lon)) group.mission_target = (float(target_lat), float(target_lon))
self.drone_map.draw_mission_plan_for_group( if expected_mission_type == 'GRID_SWEEP':
group_id, group.color, # Grid Sweep 的範圍已由矩形圖層表示,不另外顯示中心/目標點。
center_lat, center_lon, target_lat, target_lon self.drone_map.clear_mission_plan_for_group(group_id)
) else:
self.drone_map.draw_mission_plan_for_group(
group_id, group.color,
center_lat, center_lon, target_lat, target_lon
)
self._launch_verification( self._launch_verification(
context['verification_type'], drone_gps_positions, selected_drones, context['verification_type'], drone_gps_positions, selected_drones,
@ -2351,6 +2359,10 @@ class ControlStationUI(QMainWindow):
self.statusBar().showMessage("矩形座標解析失敗", 3000) self.statusBar().showMessage("矩形座標解析失敗", 3000)
return return
# 將確認後的框選範圍存入群組專屬圖層,供停止任務時精準清除。
self.drone_map.draw_grid_sweep_area_for_group(
group.group_id, group.color, rect_corners)
panel = self.group_panels.get(group.group_id) panel = self.group_panels.get(group.group_id)
params = panel.get_mission_params() if panel else {} params = panel.get_mission_params() if panel else {}
base_alt = params.get('altitude', 10.0) base_alt = params.get('altitude', 10.0)

@ -368,6 +368,8 @@ class DroneMap:
// 多群組任務規劃 每個 group 各自的 layer group // 多群組任務規劃 每個 group 各自的 layer group
var groupMissionLayers = {}; // group_id L.layerGroup var groupMissionLayers = {}; // group_id L.layerGroup
// Grid Sweep 框選範圍也依群組保存停止時可單獨清除
var gridSweepAreaLayers = {}; // group_id L.layerGroup
// 選擇工具變量 // 選擇工具變量
var selectionMode = null; // 'drones', 'rect', 'polygon', 'route', null var selectionMode = null; // 'drones', 'rect', 'polygon', 'route', null
@ -581,23 +583,6 @@ class DroneMap:
[bounds.getSouth(), bounds.getEast()], [bounds.getSouth(), bounds.getEast()],
[bounds.getSouth(), bounds.getWest()] [bounds.getSouth(), bounds.getWest()]
]; ];
L.rectangle(bounds, {
color: '#FF6B6B',
fillColor: '#FF6B6B',
fillOpacity: 0.2,
weight: 2
}).addTo(selectionLayer);
rectPoints.forEach(point => {
L.circleMarker(point, {
radius: 5,
color: '#FF6B6B',
fillColor: '#FF6B6B',
fillOpacity: 0.8
}).addTo(selectionLayer);
});
if (bridge) { if (bridge) {
var pointsStr = JSON.stringify(rectPoints); var pointsStr = JSON.stringify(rectPoints);
bridge.rectangleSelected(pointsStr); bridge.rectangleSelected(pointsStr);
@ -974,6 +959,41 @@ class DroneMap:
} }
} }
function drawGridSweepAreaForGroup(groupId, color, rectPoints) {
clearGridSweepAreaForGroup(groupId);
var layerGroup = L.layerGroup().addTo(map);
gridSweepAreaLayers[groupId] = layerGroup;
var bounds = L.latLngBounds(rectPoints);
L.rectangle(bounds, {
color: color,
fillColor: color,
fillOpacity: 0.2,
weight: 2
}).addTo(layerGroup);
rectPoints.forEach(point => {
L.circleMarker(point, {
radius: 5,
color: color,
fillColor: color,
fillOpacity: 0.8
}).addTo(layerGroup);
});
}
function clearGridSweepAreaForGroup(groupId, restartSelection) {
if (gridSweepAreaLayers[groupId]) {
map.removeLayer(gridSweepAreaLayers[groupId]);
delete gridSweepAreaLayers[groupId];
}
if (restartSelection) {
clearSelectionMode();
selectionMode = 'rect';
map.dragging.disable();
console.log('Grid Sweep: 已清除範圍並重新進入框選模式');
}
}
function clearAllMissionPlans() { function clearAllMissionPlans() {
for (var gid in groupMissionLayers) { for (var gid in groupMissionLayers) {
map.removeLayer(groupMissionLayers[gid]); map.removeLayer(groupMissionLayers[gid]);
@ -1110,6 +1130,23 @@ class DroneMap:
self.map_view.page().runJavaScript(f"clearMissionPlanForGroup('{group_id}');") self.map_view.page().runJavaScript(f"clearMissionPlanForGroup('{group_id}');")
_log("INFO", f"地圖已清除 Group {group_id} 任務規劃") _log("INFO", f"地圖已清除 Group {group_id} 任務規劃")
def draw_grid_sweep_area_for_group(self, group_id, color, rect_corners):
"""繪製指定群組的 Grid Sweep 框選範圍。"""
if self.map_loaded:
group_json = json.dumps(group_id)
color_json = json.dumps(color)
corners_json = json.dumps(rect_corners)
self.map_view.page().runJavaScript(
f"drawGridSweepAreaForGroup({group_json}, {color_json}, {corners_json});")
def clear_grid_sweep_area_for_group(self, group_id, restart_selection=False):
"""清除指定群組的 Grid Sweep 範圍,可選擇重新進入框選模式。"""
if self.map_loaded:
group_json = json.dumps(group_id)
restart_js = str(bool(restart_selection)).lower()
self.map_view.page().runJavaScript(
f"clearGridSweepAreaForGroup({group_json}, {restart_js});")
def set_mission_mode(self, mode): def set_mission_mode(self, mode):
"""從 Python 端切換地圖的任務模式(觸發框選/路徑標記等)""" """從 Python 端切換地圖的任務模式(觸發框選/路徑標記等)"""
if self.map_loaded: if self.map_loaded:

Loading…
Cancel
Save