|
|
|
|
@ -368,6 +368,8 @@ class DroneMap:
|
|
|
|
|
|
|
|
|
|
// 多群組任務規劃 — 每個 group 各自的 layer group
|
|
|
|
|
var groupMissionLayers = {}; // group_id → L.layerGroup
|
|
|
|
|
// Grid Sweep 框選範圍也依群組保存,停止時可單獨清除。
|
|
|
|
|
var gridSweepAreaLayers = {}; // group_id → L.layerGroup
|
|
|
|
|
|
|
|
|
|
// 選擇工具變量
|
|
|
|
|
var selectionMode = null; // 'drones', 'rect', 'polygon', 'route', null
|
|
|
|
|
@ -581,23 +583,6 @@ class DroneMap:
|
|
|
|
|
[bounds.getSouth(), bounds.getEast()],
|
|
|
|
|
[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) {
|
|
|
|
|
var pointsStr = JSON.stringify(rectPoints);
|
|
|
|
|
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() {
|
|
|
|
|
for (var gid in groupMissionLayers) {
|
|
|
|
|
map.removeLayer(groupMissionLayers[gid]);
|
|
|
|
|
@ -1110,6 +1130,23 @@ class DroneMap:
|
|
|
|
|
self.map_view.page().runJavaScript(f"clearMissionPlanForGroup('{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):
|
|
|
|
|
"""從 Python 端切換地圖的任務模式(觸發框選/路徑標記等)"""
|
|
|
|
|
if self.map_loaded:
|
|
|
|
|
|