Plane.FormationCreator/Plane.FormationCreator/Formation/FlightTaskManager.cs

2319 lines
89 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Plane.Collections;
using Plane.Copters;
using Plane.Geography;
using Plane.Windows.Messages;
using GalaSoft.MvvmLight;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Plane.CommunicationManagement;
using FlightRoute;
using System.IO;
using System.Windows.Media.Media3D;
using System.Diagnostics;
using Plane.FormationCreator.Util;
using System.Collections;
namespace Plane.FormationCreator.Formation
{
public class FlightTaskManager : ObservableObject
{
public FlightTaskManager(CopterManager copterManager)
{
LoadIni();
_copterManager = copterManager;
//AddTakeOffTask(_copterManager.Copters);
_copterManager.Copters.CollectionChanged += (sender, e) =>
{
// TODO: 林俊清, 20150724, 需要改为正确的做法(清除旧飞机的任务,补充新飞机的任务)。
//AddTakeOffTask(e.NewItems?.Cast<ICopter>());
};
_copterManager.SelectedCoptersChanged += (sender, e) =>
{
if (_copterManager.AcceptingControlCopters != null && _copterManager.AcceptingControlCopters.Count() == 1)
CommModuleManager.Instance.LED_FlickerAsync(_copterManager.AcceptingControlCopters);
/*
foreach (ICopter copter in _copterManager.AcceptingControlCopters)
{
copter.LEDAsync();
}
*/
// TODO: 林俊清, 20150803, 处理选中多个飞行器的情况。
if (_copterManager.SelectedCopters.Count() > 1)
{
return;
}
var selectedCopter = _copterManager.SelectedCopters.FirstOrDefault();
foreach (var task in Tasks)
{
foreach (var info in task.SingleCopterInfos)
{
if (info.Copter == selectedCopter)
{
task.ModifyingSingleCopterInfo = info;
break;
}
}
}
if (selectedCopter!=null)
selectedCopter.SetShowLEDFlashAsync(1, 100);
//if (selectedCopter != null)
//selectedCopter.LEDAsync();
};
TaskAdded += (sender, e) =>
{
// TODO: 林俊清, 20150803, 处理选中多个飞行器的情况。
if (_copterManager.SelectedCopters.Count() > 1)
{
return;
}
var selectedCopter = _copterManager.SelectedCopters.FirstOrDefault();
var task = e.AddedTask;
foreach (var info in task.SingleCopterInfos)
{
if (info.Copter == selectedCopter)
{
task.ModifyingSingleCopterInfo = info;
break;
}
}
};
}
private CopterManager _copterManager;
private string _MessageText="test";
public string MessageText
{
get { return _MessageText; }
set
{
if (Set(nameof(MessageText), ref _MessageText, value))
{
// _lastUpdateStatusTextTime = DateTime.Now;
}
}
}
private bool _TaskRun_2D = true;
public bool TaskRun_2D
{
get { return _TaskRun_2D; }
set
{
if (Set(nameof(TaskRun_2D), ref _TaskRun_2D, value))
{
}
}
}
private void AddTakeOffTask(IEnumerable<ICopter> copters)
{
if (copters == null || !copters.Any()) return;
bool takeOffTaskExisted = Tasks.Count >= 1;
FlightTask takeOffTask;
if (takeOffTaskExisted)
{
takeOffTask = Tasks[0];
}
else
{
takeOffTask = new FlightTask(FlightTaskType.TakeOff);
Tasks.Add(takeOffTask);
RaiseTaskAdded(null, takeOffTask);
//TaskAdded?.Invoke(this, new FlightTaskAddedEventArgs { AddedTask = takeOffTask });
}
foreach (var copter in copters)
{
takeOffTask.SingleCopterInfos.Add(FlightTaskSingleCopterInfo.CreateForTakeOffTask(copter, targetAlt: 15));
}
}
public ObservableCollection<FlightTask> Tasks { get; } = new ObservableCollection<FlightTask>();
public int GetTaskTime(int TaskIndex)
{
int tasktime = 0;
if ((Tasks==null)|| TaskIndex> Tasks.Count-1) return tasktime;
FlightTask value = Tasks[TaskIndex];
switch (value.TaskType)
{
case FlightTaskType.TakeOff: tasktime = value.TakeOffTime; ; break;
case FlightTaskType.FlyTo: tasktime = value.FlytoTime + value.LoiterTime; break;
//降落时间计算前一个任务目标高度最高的飞机的降落时间按1.5米/秒下降
case FlightTaskType.Land:
float maxalt = 0.0f;
for (int i = 0; i < Tasks[TaskIndex-1].SingleCopterInfos.Count; i++)
{
var copterInfo = Tasks[TaskIndex - 1].SingleCopterInfos[i];
if (maxalt < copterInfo.TargetAlt) maxalt = copterInfo.TargetAlt;
}
tasktime =(int) Math.Round(maxalt / 1.5,0);
break;
}
return tasktime;
}
private FlightTask _SelectedTask;
public FlightTask SelectedTask
{
get { return _SelectedTask; }
set
{
if (_SelectedTask != value)
{
int starttime=0;
if (_SelectedTask != null)
{
_SelectedTask.IsSelected = false;
if (TaskState == TasksStatus.Stop)
_SelectedTask.Status = FlightTaskStatus.Stop;
}
if (value != null)
{
value.IsSelected = true;
value.IsRightSelected = true;
RightSelect(value);
if (TaskState== TasksStatus.Stop)
value.Status = FlightTaskStatus.Selected;
for (int i = 0; i < value.TaskIndex; i++)
starttime += GetTaskTime(i);
TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(starttime));
string str = "";
if (ts.Hours > 0)
{
str = ts.Hours.ToString() + "小时" + ts.Minutes.ToString() + "分" + ts.Seconds + "秒";
}
if (ts.Hours == 0 && ts.Minutes > 0)
{
str = ts.Minutes.ToString() + "分" + ts.Seconds + "秒";
}
if (ts.Hours == 0 && ts.Minutes == 0)
{
str = ts.Seconds + "秒";
}
Message.ShowStatus($"选中 [{value.TaskIndex+1} {value.TaskCnName }] 从{str}开始执行,需{ GetTaskTime(value.TaskIndex)}秒");
}
else Message.ShowStatus($"无任务选中");
}
Set(nameof(SelectedTask), ref _SelectedTask, value);
}
}
private int _SelectedTaskIndex;
public int SelectedTaskIndex
{
get { return _SelectedTaskIndex; }
set { Set(nameof(SelectedTaskIndex), ref _SelectedTaskIndex, value);
// this.SelectedTask = Tasks[value];
}
}
// 右键单击任务,用于隐藏任务图标, added by ZJF
private int _RightSelectedTaskIndex;
public int RightSelectedTaskIndex
{
get { return _RightSelectedTaskIndex; }
set { Set(nameof(RightSelectedTaskIndex), ref _RightSelectedTaskIndex, value); }
}
private FlightTask _CurrentRunningTask;
public FlightTask CurrentRunningTask
{
get { return _CurrentRunningTask; }
private set { Set(nameof(CurrentRunningTask), ref _CurrentRunningTask, value); }
}
private int _CurrentRunningTaskIndex;
public int CurrentRunningTaskIndex
{
get { return _CurrentRunningTaskIndex; }
private set { Set(nameof(CurrentRunningTaskIndex), ref _CurrentRunningTaskIndex, value); }
}
private int _ColumnCount = 5;
public int ColumnCount
{
get { return _ColumnCount; }
set { Set(nameof(ColumnCount), ref _ColumnCount, value); }
}
private float _ColumnDistance = 4.0f;
public float ColumnDistance
{
get { return _ColumnDistance; }
set { Set(nameof(ColumnDistance), ref _ColumnDistance, value); }
}
private float _RowDistance = 4.0f;
public float RowDistance
{
get { return _RowDistance; }
set { Set(nameof(RowDistance), ref _RowDistance, value); }
}
private int _Orientation = 0;
public int Orientation
{
get { return _Orientation; }
set { Set(nameof(Orientation), ref _Orientation, value); }
}
private TasksStatus _TaskState = TasksStatus.Stop;
public TasksStatus TaskState
{
get { return _TaskState; }
private set { Set(nameof(TaskState), ref _TaskState, value); }
}
public event EventHandler<FlightTaskAddedEventArgs> TaskAdded;
public event EventHandler<FlightTaskDeledEventArgs> TaskDeled;
public void RaiseTaskDeled(FlightTask vDeledTask,int vTaskIndex)
{
try
{
TaskDeled?.Invoke(this, new FlightTaskDeledEventArgs { DeledTask = vDeledTask, TaskIndex= vTaskIndex });
}
catch (Exception ex)
{
//RaiseExceptionThrown(ex);
}
}
public void RaiseTaskAdded(FlightTask lastTask ,FlightTask newTask)
{
try
{
TaskAdded?.Invoke(this, new FlightTaskAddedEventArgs { LastTask = lastTask, AddedTask = newTask });
}
catch (Exception ex)
{
//RaiseExceptionThrown(ex);
}
newTask.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case nameof(FlightTask.TaskTypeIndex):
case nameof(FlightTask.TaskCnName):
TaskTypeChanged?.Invoke(this, new FlightTaskTypeChangedEventArgs((FlightTask)sender));
TaskcnNameChanged?.Invoke(this, new FlightTaskcnNameChangedEventArgs((FlightTask)sender));
break;
default:
break;
}
};
}
public event EventHandler<FlightTaskAddedOriginalEventArgs> OnOriginalSet;
public event EventHandler<SingleCopterInfoChangedEventArgs> SingleCopterInfoChanged;
public void RaiseSingleCopterTaskChanged(FlightTaskSingleCopterInfo singleCopterInfo)
{
SingleCopterInfoChanged?.Invoke(this, new SingleCopterInfoChangedEventArgs(singleCopterInfo));
}
public event EventHandler<FlightTaskTypeChangedEventArgs> TaskTypeChanged;
public event EventHandler<FlightTaskcnNameChangedEventArgs> TaskcnNameChanged;
public event EventHandler TasksCleared;
public void AddTask()
{
//if (AppEx.Instance.CurrentMode == AppMode.PreparedForRunningTasks)
{
var copters = _copterManager.Copters;
if (!copters.Any()) return;
AppEx.Current.AppMode = AppMode.ModifyingTask;
if (Tasks.Count == 0)
AddTakeOffTask(copters);
var lastTask = Tasks.LastOrDefault();
if (SelectedTask !=null)
lastTask = SelectedTask;
var nullableCenter = copters.GetCenter();
if (nullableCenter == null) return;
var center = nullableCenter.Value;
var newTask = new FlightTask(FlightTaskType.FlyTo);
int coptindex = 0;
int colnum = ColumnCount; //自动生成列数=4
float coldis = ColumnDistance;//列相距5米
float rowdis = RowDistance;//行相距5米
float matrixdis = 20; //生成方阵距离30米
int orientation = Orientation;
int currcol = 0; //当前列号
int currrow = 0; //当前行
Tuple<double, double> colLatLng = new Tuple<double, double>(0, 0);
Tuple<double, double> targetLatLng = new Tuple<double, double>(0, 0);
FlightTaskSingleCopterInfo lastSingleCopterInfo = null;
FlightTaskSingleCopterInfo preSingleCopterInfo = null;
foreach (var copter in copters)
{
preSingleCopterInfo = lastTask.SingleCopterInfos.Find(info => info.Copter == copter);
if (coptindex == 0)
{
lastSingleCopterInfo = lastTask.SingleCopterInfos.Find(info => info.Copter == copter);
targetLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(lastSingleCopterInfo.TargetLat, lastSingleCopterInfo.TargetLng, orientation, matrixdis);
colLatLng = targetLatLng;
}
else
{
if (currcol < colnum)
targetLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(colLatLng.Item1, colLatLng.Item2, orientation + 90, currcol * coldis);
else
{
currrow++;
currcol = 0;
targetLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(colLatLng.Item1, colLatLng.Item2, orientation + 180, rowdis);
colLatLng = targetLatLng;
}
}
currcol++;
coptindex++;
var newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(copter, targetLatLng.Item1, targetLatLng.Item2, preSingleCopterInfo.TargetAlt);
newTask.SingleCopterInfos.Add(newSingleCopterInfo);
}
int selindex = SelectedTaskIndex+1;
Tasks.Insert(SelectedTaskIndex+1, newTask);
RaiseTaskAdded(lastTask, newTask);
SelectTask(selindex);
/*
Tasks.Add(newTask);
RaiseTaskAdded(lastTask, newTask);
SelectedTask = newTask;
SelectedTaskIndex = Tasks.Count - 1;
*/
}
}
//是否显示计划航线
private bool _showroute = true;
public bool showroute
{
get { return _showroute; }
set { Set(nameof(showroute), ref _showroute, value); }
}
private double _OriginLat = 0;
public double OriginLat
{
get { return _OriginLat; }
set { Set(nameof(OriginLat), ref _OriginLat, value); }
}
private double _OriginLng = 0;
public double OriginLng
{
get { return _OriginLng; }
set { Set(nameof(OriginLng), ref _OriginLng, value); }
}
/// <summary>
/// 起始点作为参考,设置起始点后飞行写入的数据将为相对坐标
/// </summary>
public void SetOriginal()
{
OnOriginalSet?.Invoke(this, new FlightTaskAddedOriginalEventArgs { Lat = OriginLat, Lng = OriginLng });
}
public void ClearTasks()
{
ResetTasks();
this.Tasks.Clear();
SelectedTask = null;
SelectedTaskIndex = 0;
//取消删除事件
/*
if (TaskDeled != null)
{
Delegate[] dels = TaskDeled.GetInvocationList();
if (dels != null)
{
foreach (Delegate d in dels)
{
TaskDeled -= d as EventHandler<FlightTaskDeledEventArgs>;
}
}
}
*/
TasksCleared?.Invoke(this, EventArgs.Empty);
// AddTakeOffTask(_copterManager.Copters);
}
//删除选中的任务
public void DelSelectedTask()
{
if (SelectedTask == null) return;
if (SelectedTask.TaskType == FlightTaskType.TakeOff) return;
int selindex = SelectedTaskIndex;
// ResetTasks();
SelectedTask.SingleCopterInfos.Clear();
Tasks.RemoveAt(SelectedTaskIndex);
RaiseTaskDeled(SelectedTask,SelectedTaskIndex);
SelectTask(selindex - 1);
// SelectedTaskIndex = 0;
}
public async Task ForceNextTasks()
{
if (CurrentRunningTaskIndex == Tasks.Count - 1)
return;
Pause();
int i = 0;
//等待暂停或2s超时(80*25ms)
while ((TaskState != TasksStatus.Paused)||(i>80))
{
await Task.Delay(25).ConfigureAwait(false);
i++;
}
if (TaskState == TasksStatus.Paused)
{
CurrentRunningTask.Status = FlightTaskStatus.Stop;
CurrentRunningTask = null;
//起飞任务需要跳过
// if (CurrentRunningTaskIndex == 0)
// CurrentRunningTaskIndex++;
CurrentRunningTaskIndex++;
await RunTaskAsync();
}
}
//指定任务开始模拟
public async Task FlyToTasks()
{
var copters = _copterManager.Copters;
if ((SelectedTaskIndex==-1) ||(TaskState == TasksStatus.Stop))
return;
int vSelectedTaskIndex= SelectedTaskIndex;
Pause();
int i = 0;
//等待暂停或2s超时(80*25ms)
while ((TaskState != TasksStatus.Paused) || (i > 80))
{
await Task.Delay(25).ConfigureAwait(false);
i++;
}
if (SelectedTaskIndex == -1)
return;
if (TaskState == TasksStatus.Paused)
{
CurrentRunningTask.Status = FlightTaskStatus.Stop;
CurrentRunningTask = null;
CurrentRunningTaskIndex = SelectedTaskIndex;
//设置所有模拟飞机的位置
for (int j = 0; j < copters.Count; j++)
{
var copter = copters[j];
var fc = copter as FakeCopter;
float targalt = 0.0f;
double lat = 0.0f;
double lng = 0.0f;
//飞机回到前一个任务位置,
//起飞任务直接用当前起飞任务位置
if (Tasks[SelectedTaskIndex].TaskType == FlightTaskType.TakeOff)
{
lat = Tasks[SelectedTaskIndex].SingleCopterInfos[j].TargetLat;
lng = Tasks[SelectedTaskIndex].SingleCopterInfos[j].TargetLng;
targalt = 0.0f;
}
else
{
//返航点直接设置起飞位置
if (Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].IsLandWaypoint)
{
lat = Tasks[0].SingleCopterInfos[j].TargetLat;
lng = Tasks[0].SingleCopterInfos[j].TargetLng;
}
else
{
//用前一个任务目标位置
lat = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].TargetLat;
lng = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].TargetLng;
}
//如果前一个是起飞任务,没有目标高度,用当前的
if (Tasks[SelectedTaskIndex - 1].TaskType == FlightTaskType.TakeOff)
targalt = Tasks[SelectedTaskIndex].SingleCopterInfos[j].TargetAlt;
else
targalt = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].TargetAlt;
}
fc.SetProperties(
latitude: lat,
longitude: lng,
altitude: targalt
);
}
//起飞任务需要跳过
// if (CurrentRunningTaskIndex == 0)
// CurrentRunningTaskIndex++;
await RunTaskAsync();
}
}
public async Task ResetTasks()
{
var copters = _copterManager.Copters;
if (Tasks.Count == 0) return;
if (TaskState == TasksStatus.Running)
{
Pause();
//等待暂停或2s超时(80*25ms)
int k = 0;
while ((TaskState != TasksStatus.Paused) || (k > 80))
{
await Task.Delay(25).ConfigureAwait(false);
k++;
}
}
TaskState = TasksStatus.Stop;
CurrentRunningTaskIndex = 0;
if (CurrentRunningTask != null)
{
CurrentRunningTask.Status = FlightTaskStatus.Stop;
CurrentRunningTask = null;
}
for (int i = 0; i < Tasks.Count; i++)
{
// 将起飞的阶段标志位都置位0
if (Tasks[i].TaskType == FlightTaskType.TakeOff)
{
var infos = Tasks[i].SingleCopterInfos;
for (int j = 0; j < infos.Count; j++)
{
var info = infos[j];
info.takeOffStage = 0;
}
}
}
//设置所有模拟飞机的位置
for (int j = 0; j < copters.Count; j++)
{
var copter = copters[j];
var fc = copter as FakeCopter;
if (fc != null)
{
fc.SetProperties(
latitude: Tasks[0].SingleCopterInfos[j].TargetLat,
longitude: Tasks[0].SingleCopterInfos[j].TargetLng,
altitude: 0 );
//设置灯光为默认颜色
fc.LEDColor = CopterManager.CopterDefaultColor;// "000000";
}
}
}
public string ExportC4DFlytoTask()
{
int count = SelectedTask.SingleCopterInfos.Count();
//string[] lines = new string[count];
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++)
{
var singleCopterInfo = SelectedTask.SingleCopterInfos[i];
double x = 100 * GeographyUtils.CalcDistance(OriginLat, OriginLng, 0,
OriginLat, singleCopterInfo.TargetLng, 0);
if (singleCopterInfo.TargetLng < OriginLng) x = -x;
double y = 100 * singleCopterInfo.TargetAlt;
double z = 100 * GeographyUtils.CalcDistance(OriginLat, OriginLng, 0,
singleCopterInfo.TargetLat, OriginLng, 0);
if (singleCopterInfo.TargetLat < OriginLat) z = -z;
sb.AppendLine($"{i + 1} 0 {x} {y} {z}");
//lines[i] = $"{i+1} {x} {y} {z}";
}
return sb.ToString().Trim();
}
//导入外部航点
public void ImportDlltoTask(string filename)
{
Vector3[] vc;
string extname = Path.GetExtension(filename);
if (extname == ".svg")
{
vc = FlyBase.svgToPos(filename);
}
else if (extname == ".obj")
{
vc = FlyBase.objToPos(filename);
}
else return;
if (vc.Count()!= _copterManager.Copters.Count)
{
Alert.Show($"飞机数量不匹配!导入{vc.Count()}架,实际{_copterManager.Copters.Count}");
return;
}
var lastTask = Tasks.LastOrDefault();
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = true, FlytoTime = 10, LoiterTime = 1 };
newTask.TaskCnName = Path.GetFileNameWithoutExtension(filename).Substring(0,6);
int id =0;
foreach (Vector3 item in vc)
{
Tuple<double, double> observationLatLng = null;
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
OriginLat,
OriginLng,
90,
(float)item.x / 100);
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
observationLatLng.Item1,
observationLatLng.Item2,
0,
(float)item.z / 100);
var thisSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
_copterManager.Copters[id++], new LatLng(observationLatLng.Item1 - OriginLat, observationLatLng.Item2 - OriginLng),
(float)item.y / 100, false);
newTask.SingleCopterInfos.Add(thisSingleCopterInfo);
}
Tasks.Add(newTask);
RaiseTaskAdded(lastTask, newTask);
}
public void ImportC4DFlytoTask(string txt)
{
string[] lines = txt.Replace("\r\n", "\n").Split('\n');
if (lines.Length % (_copterManager.Copters.Count + 1) != 0)
{
Alert.Show("文件内容错误!");
return;
}
int taskCount = lines.Length / (_copterManager.Copters.Count + 1);
int startIndex;
string line;
Dictionary<int, string[]> PointDic;
for (int i = 0; i < taskCount; i++)
{
startIndex = i * (_copterManager.Copters.Count + 1);
string taskName = lines[startIndex];
PointDic = new Dictionary<int, string[]>();
for (int j = 0; j < _copterManager.Copters.Count; j++)
{
line = lines[startIndex + j + 1];
string[] parameters = line.Split(' ');
int id = Convert.ToInt32(parameters[0]);
string frame = parameters[1];
string[] point = new string[3];
point[0] = parameters[1]; //左右 经度
point[1] = parameters[2]; //上下 高度
point[2] = parameters[3]; //前后 纬度
PointDic.Add(id, point);
}
var lastTask = Tasks.LastOrDefault();
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = true, FlytoTime = 10, LoiterTime = 1 };
newTask.TaskCnName = taskName;
for (int k = 0; k < PointDic.Count; k++)
{
string[] point = PointDic[k + 1];
//string frame = parameters[1];
string x = point[0]; //左右 经度
string y = point[1]; //上下 高度
string z = point[2]; //前后 纬度
Tuple<double, double> observationLatLng = null;
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
OriginLat,
OriginLng,
90,
Convert.ToSingle(x) / 100);
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
observationLatLng.Item1,
observationLatLng.Item2,
0,
Convert.ToSingle(z) / 100);
var thisSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
_copterManager.Copters[k], new LatLng(observationLatLng.Item1 - OriginLat, observationLatLng.Item2 - OriginLng),
Convert.ToSingle(y) / 100, false);
newTask.SingleCopterInfos.Add(thisSingleCopterInfo);
}
Tasks.Add(newTask);
RaiseTaskAdded(lastTask, newTask);
}
// Alert.Show("导入完成!");
/*
Dictionary<int, string[]> PointDic = new Dictionary<int, string[]>();
foreach (string line in lines)
{
string[] parameters = line.Split(' ');
int id = Convert.ToInt32(parameters[0]);
string frame = parameters[1];
string[] point = new string[3];
point[0] = parameters[1]; //左右 经度
point[1] = parameters[2]; //上下 高度
point[2] = parameters[3]; //前后 纬度
PointDic.Add(id, point);
}
var lastTask = Tasks.LastOrDefault();
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = true, FlytoTime = 10, LoiterTime = 10 };
for (int i = 0; i < PointDic.Count; i++)
{
string[] point = PointDic[i + 1];
//string frame = parameters[1];
string x = point[0]; //左右 经度
string y = point[1]; //上下 高度
string z = point[2]; //前后 纬度
Tuple<double, double> observationLatLng = null;
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
OriginLat,
OriginLng,
90,
Convert.ToSingle(x) / 100);
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
observationLatLng.Item1,
observationLatLng.Item2,
0,
Convert.ToSingle(z) / 100);
var thisSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
_copterManager.Copters[i], new LatLng(observationLatLng.Item1 - OriginLat, observationLatLng.Item2 - OriginLng),
Convert.ToSingle(y)/100, false);
newTask.SingleCopterInfos.Add(thisSingleCopterInfo);
}
Tasks.Add(newTask);
TaskAdded?.Invoke(this, new FlightTaskAddedEventArgs { LastTask = lastTask, AddedTask = newTask });
*/
}
public void ImportBlenderFlyToTask(string blenderVectors)
{
string[] lineVectors = blenderVectors.Replace("\r\n","\n").Split('\n');
var lastTask = Tasks.LastOrDefault();
float alt = lastTask.SingleCopterInfos[0].TargetAlt;
double lat = lastTask.SingleCopterInfos[0].LatLngOffset.Lat;
double lng = lastTask.SingleCopterInfos[0].LatLngOffset.Lng;
foreach (var item in lineVectors)
{
string vector = item.Replace("Vector((", "").Replace("))", "");
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = true, FlytoTime = 1, LoiterTime = 0 };
string[] vectors = vector.Split(',');
double x = double.Parse(vectors[1]);
double y = double.Parse(vectors[0]);
int x_directionDegrees = x > 0 ? 90 : -90;
int y_directionDegrees = y > 0 ? 0 : 180;
Tuple<double, double> observationLatLng = null;
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
lat,
lng,
90,
(float)x);
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
observationLatLng.Item1,
observationLatLng.Item2,
0,
(float)y);
var newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
_copterManager.Copters[0], new LatLng((double)observationLatLng.Item1,
(double)observationLatLng.Item2), alt, false);
newTask.SingleCopterInfos.Add(newSingleCopterInfo);
Tasks.Add(newTask);
RaiseTaskAdded(lastTask, newTask);
Message.Show(vector);
}
}
public void RestoreFlyToTask(bool staggerRoutes, int flytoTime, int loiterTime, string taskName, dynamic singleCopterInfos, bool isMeter)
{
var copters = _copterManager.Copters;
float tagalt = 15;
if (!copters.Any()) return;
AppEx.Current.AppMode = AppMode.ModifyingTask;
var lastTask = Tasks.LastOrDefault();
var nullableCenter = copters.GetCenter();
if (nullableCenter == null) return;
var center = nullableCenter.Value;
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = staggerRoutes, FlytoTime = flytoTime, LoiterTime = loiterTime };
if(taskName != null) newTask.TaskCnName = taskName;
// TODO: 林俊清, 20150801, 处理实际飞行器数目与记录中数目不一致的情况。
for (int i = 0; i < copters.Count; i++)
{
var copter = copters[i];
FlightTaskSingleCopterInfo newSingleCopterInfo;
if (i < singleCopterInfos.Count)
{
var singleCopterInfoObj = singleCopterInfos[i];
tagalt = (float)singleCopterInfoObj.targetAlt;
if (isMeter)
newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
copter,
(double)singleCopterInfoObj.x,
(double)singleCopterInfoObj.y,
(float)singleCopterInfoObj.targetAlt - copter.GroundAlt,
(bool)singleCopterInfoObj.isLandWaypoint);
else
newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
copter,
new LatLng((double)singleCopterInfoObj.latOffset, (double)singleCopterInfoObj.lngOffset),
(float)singleCopterInfoObj.targetAlt - copter.GroundAlt, (bool)singleCopterInfoObj.isLandWaypoint);
var jsonArray = singleCopterInfoObj.ledInfos as Newtonsoft.Json.Linq.JArray;
ObservableCollection<LEDInfo> ledList = jsonArray.ToObject<ObservableCollection<LEDInfo>>();
foreach(LEDInfo info in ledList)
{
newSingleCopterInfo.AddLEDInfo(info);
}
if (singleCopterInfoObj.isChangeSpeed != null)
{
bool isChangeSpeed = (bool)singleCopterInfoObj.isChangeSpeed;
if (isChangeSpeed)
{
newSingleCopterInfo.IsChangeSpeed = isChangeSpeed;
newSingleCopterInfo.LevelSpeed = (float)singleCopterInfoObj.levelSpeed;
newSingleCopterInfo.UpSpeed = (float)singleCopterInfoObj.upSpeed;
newSingleCopterInfo.DownSpeed = (float)singleCopterInfoObj.downSpeed;
}
}
}
else
{
//实际飞机比保存的任务计划的飞机多,多的飞机设置默认航点
newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask
(copter, (double)copter.Latitude, (double)copter.Longitude, tagalt);
}
newTask.SingleCopterInfos.Add(newSingleCopterInfo);
}
Tasks.Add(newTask);
RaiseTaskAdded(lastTask, newTask);
}
private void RestoreTakeOffTask(byte takeOffTime, dynamic singleCopterInfos)
{
var copters = _copterManager.Copters;
if (copters == null || !copters.Any()) return;
AppEx.Current.AppMode = AppMode.ModifyingTask;
var lastTask = Tasks.LastOrDefault();
FlightTask takeOffTask = Tasks[0];
takeOffTask.TakeOffTime = takeOffTime;
for (int i = 0; i < copters.Count; i++)
{
var singleCopterInfoObj = singleCopterInfos[i];
takeOffTask.SingleCopterInfos[i].TakeOffWaitTime = (ushort)singleCopterInfoObj.waitTime;
if (singleCopterInfoObj.ledInfos!= null)
{
var jsonArray = singleCopterInfoObj.ledInfos as Newtonsoft.Json.Linq.JArray;
ObservableCollection<LEDInfo> ledList = jsonArray.ToObject<ObservableCollection<LEDInfo>>();
foreach (LEDInfo info in ledList)
{
takeOffTask.SingleCopterInfos[i].AddLEDInfo(info);
}
}
//Message.Show(((ushort)singleCopterInfoObj.waitTime).ToString());
}
}
private void RestoreLandTask(dynamic singleCopterInfos)
{
var copters = _copterManager.Copters;
if (copters == null || !copters.Any()) return;
AppEx.Current.AppMode = AppMode.ModifyingTask;
var lastTask = Tasks.LastOrDefault();
var LandTask = new FlightTask(FlightTaskType.Land);
for (int i = 0; i < copters.Count; i++)
{
var copter = copters[i];
FlightTaskSingleCopterInfo newSingleCopterInfo;
var singleCopterInfoObj = singleCopterInfos[i];
newSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForLandTask(copter, (int)singleCopterInfoObj.waitTime);
LandTask.SingleCopterInfos.Add(newSingleCopterInfo);
}
Tasks.Add(LandTask);
RaiseTaskAdded(lastTask, LandTask);
}
//导出任务 (单位:米)
public IEnumerable<object> ExportTasksToMeter()
{
var tasks = Tasks.Select<FlightTask, object>(task =>
{
var type = task.TaskType;
switch (type)
{
case FlightTaskType.TakeOff:
return new {
type = type,
takeoffnumber = 1,// TakeOffNumAttr,
takeoffTime = task.TakeOffTime,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
return new
{
waitTime = info.TakeOffWaitTime,
ledInfos = info.LEDInfos
};
})
};
case FlightTaskType.FlyTo:
return new
{
type = type,
staggerRoutes = task.StaggerRoutes,
flytoTime = task.FlytoTime,
loiterTime = task.LoiterTime,
taskname = task.TaskCnName,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
var offset = info.LatLngOffset;
return new
{
x = info.X,
y = info.Y,
targetAlt = info.TargetAlt + info.Copter.GroundAlt, //导出时加上地面摆放高度,导入后若没有摆放高度,模拟就会清楚的看到高度错误
//showLED = info.FlytoShowLED,
ledInfos = info.LEDInfos,
isLandWaypoint = info.IsLandWaypoint,
isChangeSpeed = info.IsChangeSpeed,
levelSpeed = info.LevelSpeed,
upSpeed = info.UpSpeed,
downSpeed = info.DownSpeed
};
})
};
case FlightTaskType.Land:
{
return new
{
type = type,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
return new
{
waitTime = info.LandWaitTime
};
})
};
}
default:
throw new NotImplementedException(type + " task export not implemented.");
}
});
return tasks;
}
//导出任务
public IEnumerable<object> ExportTasks()
{
// For reference.
//var tasks = new object[]
//{
// new
// {
// type = FlightTaskType.TakeOff,
// },
// new
// {
// type = FlightTaskType.FlyTo,
// staggerRoutes = false,
// singleCopterInfos = new object[] {
// new {
// latOffset = 0.0001,
// lngOffset = 0.0001,
// targetAlt = 10
// },
// new {
// latOffset = 0.0003,
// lngOffset = 0.0003,
// targetAlt = 15
// }
// }
// },
// new
// {
// type = FlightTaskType.Turn,
// singleCopterInfos = new object[] {
// new {
// latOffset = 0.0001,
// lngOffset = 0.0001,
// targetAlt = 10,
// targetHeading = 90
// },
// new {
// latOffset = 0.0001,
// lngOffset = 0.0001,
// targetAlt = 10,
// targetHeading = 270
// }
// }
// },
// new
// {
// type = FlightTaskType.Circle,
// singleCopterInfos = new object[] {
// new {
// latOffset = 0.0001,
// lngOffset = 0.0001,
// targetAlt = 10,
// centerDirectionDeg = 90,
// radius = 1000,
// rate = 20,
// turns = 1,
// channel3 = 1500
// },
// new {
// latOffset = 0.0003,
// lngOffset = 0.0003,
// targetAlt = 15,
// centerDirectionDeg = 270,
// radius = 1000,
// rate = 20,
// turns = 1,
// channel3 = 1500
// }
// }
// },
// new
// {
// type = FlightTaskType.SimpleCircle,
// singleCopterInfos = new object[] {
// new {
// latOffset = 0.0001,
// lngOffset = 0.0001,
// targetAlt = 10,
// rate = 20,
// turns = 1,
// channel3 = 1500
// },
// new {
// latOffset = 0.0003,
// lngOffset = 0.0003,
// targetAlt = 15,
// rate = 20,
// turns = 1,
// channel3 = 1500
// }
// }
// }
//};
var tasks = Tasks.Select<FlightTask, object>(task =>
{
var type = task.TaskType;
switch (type)
{
case FlightTaskType.TakeOff:
return new {
type = type,
takeoffnumber = 1,//TakeOffNumAttr,
takeoffTime = task.TakeOffTime,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
return new
{
waitTime = info.TakeOffWaitTime,
ledInfos = info.LEDInfos
};
})
};
case FlightTaskType.FlyTo:
return new
{
type = type,
staggerRoutes = task.StaggerRoutes,
flytoTime = task.FlytoTime,
loiterTime = task.LoiterTime,
taskname = task.TaskCnName,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
var offset = info.LatLngOffset;
return new
{
latOffset = offset.Lat,
lngOffset = offset.Lng,
targetAlt = info.TargetAlt + info.Copter.GroundAlt, //导出时加上地面摆放高度,导入后若没有摆放高度,模拟就会清楚的看到高度错误
//showLED = info.FlytoShowLED,
ledInfos = info.LEDInfos,
isLandWaypoint = info.IsLandWaypoint,
isChangeSpeed = info.IsChangeSpeed,
levelSpeed = info.LevelSpeed,
upSpeed = info.UpSpeed,
downSpeed = info.DownSpeed
};
})
};
case FlightTaskType.Land:
{
return new
{
type = type,
singleCopterInfos = task.SingleCopterInfos.Select(info =>
{
return new
{
waitTime = info.LandWaitTime
};
})
};
}
default:
throw new NotImplementedException(type + " task export not implemented.");
}
});
return tasks;
}
//导入任务,可设置导入哪些步骤
public void ImportTasksindex(dynamic tasks, int startindex,int endindex, bool isMeter)
{
var copters = _copterManager.Copters;
if (Tasks.Count == 0)
AddTakeOffTask(copters);
int i =1;
foreach (var task in tasks)
{
if ((i >= startindex)&& (i <= endindex))
{
switch ((FlightTaskType)task.type)
{
case FlightTaskType.TakeOff:
// AddTakeOffTask(copters); // added by ZJF
// TakeOffNumAttr = task.takeoffnumber;
// TakeOffNumAttr= task.takeoffnumber;
RestoreTakeOffTask((byte)task.takeoffTime, task.singleCopterInfos);
break;
case FlightTaskType.FlyTo:
RestoreFlyToTask((bool)task.staggerRoutes, (int)task.flytoTime, (int)task.loiterTime, (string)task.taskname, task.singleCopterInfos, isMeter);
break;
case FlightTaskType.Land:
RestoreLandTask(task.singleCopterInfos);
break;
}
}
i++;
}
}
//计算中心点 (三维的)
private Point3D CenterFormMeter(List<Point3D> point1, List<Point3D> point2)
{
Point3D centerPoint = new Point3D(0, 0, 0);
if (point1.Count != point2.Count) return centerPoint;
double minX = point1[0].X;
double maxX = point1[0].X;
double minY = point1[0].Y;
double maxY = point1[0].Y;
double minZ = point1[0].Z;
double maxZ = point1[0].Z;
int count = point1.Count;
for (int i = 0; i < count; i++)
{
minX = Math.Min(minX, Math.Min(point1[i].X, point2[i].X));
maxX = Math.Max(maxX, Math.Min(point1[i].X, point2[i].X));
minY = Math.Min(minY, Math.Min(point1[i].Y, point2[i].Y));
maxY = Math.Max(maxY, Math.Max(point1[i].Y, point2[i].Y));
minZ = Math.Min(minZ, Math.Min(point1[i].Z, point2[i].Z));
maxZ = Math.Max(maxZ, Math.Max(point1[i].Z, point2[i].Z));
}
centerPoint.X = (minX + maxX) / 2;
centerPoint.Y = (minY + maxY) / 2;
centerPoint.Z = (minZ + maxZ) / 2;
return centerPoint;
}
public double SumFlyLines(List<FlightTaskSingleCopterInfo> preinfos, List<FlightTaskSingleCopterInfo> currinfos)
{
double sumdis = 0;
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
//当前任务
Point3D preLoc = new Point3D(preinfos[i].X, preinfos[i].Y, preinfos[i].TargetAlt);
Point3D curLoc = new Point3D(currinfos[i].X, currinfos[i].Y, currinfos[i].TargetAlt);
//算距离
sumdis += Point3D.Subtract(curLoc, preLoc).Length;
}
return sumdis;
}
public void SetAllTaskFlytime()
{
for (int taskIndex = 1; taskIndex < Tasks.Count; taskIndex++)
SetTaskFlytime(taskIndex);
}
public void SetTaskFlytime(int taskIndex,bool settime=true)
{
if ((taskIndex > 0 )&&(taskIndex < Tasks.Count) &&( Tasks[taskIndex].TaskType == FlightTaskType.FlyTo))
{
if (_copterManager.Copters.Count() > 0)
{
double maxDistance = 0.0f;
string copterName = "";
double speed = 0.0f;
foreach (var copter in _copterManager.Copters)
{
var prevWaypoint = Tasks[taskIndex - 1].SingleCopterInfos.FirstOrDefault(c => c.Copter == copter);
var curWaypoint = Tasks[taskIndex].SingleCopterInfos.FirstOrDefault(c => c.Copter == copter);
if ((curWaypoint.IsChangeSpeed) && (curWaypoint.LevelSpeed == -1))
{
Message.Show($"任务{taskIndex + 1}飞机编号:{copter.Id}是自动速度,无法计算时间!");
return ;
}
double distance = GeographyUtils.CalcDistance(
prevWaypoint.TargetLat, prevWaypoint.TargetLng, prevWaypoint.TargetAlt,
curWaypoint.TargetLat, curWaypoint.TargetLng, curWaypoint.TargetAlt);
if (distance > maxDistance)
{
maxDistance = distance;
copterName = copter.Name;
speed = curWaypoint.LevelSpeed;
}
}
double time = CalculateFlyIime(maxDistance, speed);
Message.Show($"任务{taskIndex+1}最大航点间距 = {Math.Round(maxDistance, 2)}米, 水平速度={Math.Round(speed, 2)}, 飞行时间 = {Math.Round(time, 2)}秒, 飞机编号:{copterName}");
if (settime)
Tasks[taskIndex].FlytoTime = (int)Math.Round(time, 2);
}
}
return ;
}
public static double CalculateFlyIime(double s, double v)
{
double t;
double a = 1; //加速度1米每秒
double at = v / a;
double a_s = 0.5f * a * at * at;
if (a_s > (s / 2)) //还没到特定速度就到了中点了
{
t = (float)System.Math.Sqrt(s / a) * 2;
}
else
{
t = (s - a_s * 2) / v + at * 2;
}
return t;
} //计算优化线路,采用米计算
/// <summary>
///
/// </summary>
/// <param name="Is3d">3D计算</param>
/// <param name="Ischange">是否改变线路的结束点顺序--返回起飞点航线不能交换</param>
public void OptimizeRouteMeter(bool Is3d=false,bool Ischange=true)
{
Dictionary<int, Point3D> curTaskPoint = new Dictionary<int, Point3D>();
Dictionary<int, Point3D> prevTaskPoint = new Dictionary<int, Point3D>();
var stopWatch = new Stopwatch();
stopWatch.Start();
//获取当前航点与前一航点所有经纬高
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
//当前任务
var curinfo = SelectedTask.SingleCopterInfos[i];
Point3D curLoc = new Point3D(curinfo.X, curinfo.Y, curinfo.TargetAlt);
curTaskPoint.Add(i, curLoc);
//前一任务
var prevInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i];
Point3D prevLoc = new Point3D(prevInfo.X, prevInfo.Y, prevInfo.TargetAlt);
prevTaskPoint.Add(i, prevLoc);
}
//Dictionary<int, Point3D> RouteRes = Util.OptimizeRoute.GenRoute(curTaskPoint, prevTaskPoint);
if (Is3d)
{
ArrayList resarray = Util.OptimizeRoute.Gen3DRoute(curTaskPoint.Values.ToArray(), prevTaskPoint.Values.ToArray());
Vector3[] RouteRes;
//最终
RouteRes = (Vector3[])resarray[0];
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].X = RouteRes[i].x;
SelectedTask.SingleCopterInfos[i].Y = RouteRes[i].y;
SelectedTask.SingleCopterInfos[i].TargetAlt = (float)RouteRes[i].z;
}
SetTaskFlytime(SelectedTaskIndex);
}
else
{
ArrayList resarray = Util.OptimizeRoute.Gen2DRoute(curTaskPoint.Values.ToArray(), prevTaskPoint.Values.ToArray(), Ischange);
Vector3[] RouteRes;
//有错层需要插入2个错层任务
if (resarray.Count == 3)
{
//选中前一个任务,插入错层
SelectTask(SelectedTaskIndex - 1);
AddTask();
//第一个错层
RouteRes = (Vector3[])resarray[0];
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].X = RouteRes[i].x;
SelectedTask.SingleCopterInfos[i].Y = RouteRes[i].y;
SelectedTask.SingleCopterInfos[i].TargetAlt = (float)RouteRes[i].z;
}
SetTaskFlytime(SelectedTaskIndex);
//第二个错层
AddTask();
RouteRes = (Vector3[])resarray[1];
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].X = RouteRes[i].x;
SelectedTask.SingleCopterInfos[i].Y = RouteRes[i].y;
SelectedTask.SingleCopterInfos[i].TargetAlt = (float)RouteRes[i].z;
}
SetTaskFlytime(SelectedTaskIndex);
SelectTask(SelectedTaskIndex + 1);
//最终
RouteRes = (Vector3[])resarray[2];
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].X = RouteRes[i].x;
SelectedTask.SingleCopterInfos[i].Y = RouteRes[i].y;
SelectedTask.SingleCopterInfos[i].TargetAlt = (float)RouteRes[i].z;
}
SetTaskFlytime(SelectedTaskIndex);
}
else
{
//最终
RouteRes = (Vector3[])resarray[0];
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].X = RouteRes[i].x;
SelectedTask.SingleCopterInfos[i].Y = RouteRes[i].y;
SelectedTask.SingleCopterInfos[i].TargetAlt = (float)RouteRes[i].z;
}
SetTaskFlytime(SelectedTaskIndex);
}
}
stopWatch.Stop();
double sumlength = SumFlyLines(Tasks[SelectedTaskIndex - 1].SingleCopterInfos, SelectedTask.SingleCopterInfos);
Message.Show($"计算用时:{stopWatch.Elapsed.TotalMilliseconds}ms,总飞行距离{sumlength}米");
return;
}
//计算优化线路,采用经纬度计算
public void OptimizeRouteNew()
{
Dictionary<int, PLLocation> curTaskPoint = new Dictionary<int, PLLocation>();
Dictionary<int, PLLocation> prevTaskPoint = new Dictionary<int, PLLocation>();
var stopWatch = new Stopwatch();
stopWatch.Start();
//获取当前航点与前一航点所有经纬高
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
//当前任务
var curinfo = SelectedTask.SingleCopterInfos[i];
PLLocation curLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng, curinfo.TargetAlt);
curTaskPoint.Add(i, curLoc);
//前一任务
var prevInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i];
PLLocation prevLoc = new PLLocation(prevInfo.TargetLat, prevInfo.TargetLng, prevInfo.TargetAlt);
prevTaskPoint.Add(i, prevLoc);
}
// int sss = Plane.AutoLine.CalAutoLine(curTaskPoint, prevTaskPoint);
// Message.Show($"中心点:{sss}");
double farDistance;
double nearDistance;
int index;
Dictionary<int, PLLocation> recordLatLng = new Dictionary<int, PLLocation>();
while (curTaskPoint.Count > 0)
{
farDistance = double.MinValue;
PLLocation centerLatLng = CenterLatLng(curTaskPoint.Values.ToList(), prevTaskPoint.Values.ToList());
index = 0;
//计算两个列表距离中心最远距离
// Message.Show($"有{curTaskPoint.Count}个点,当前中心点:{centerLatLng.Longitude},{centerLatLng.Latitude},{centerLatLng.Altitude}");
double distance1;
bool farIsCurTaskPoint = true;
foreach (var item in curTaskPoint)
{
distance1 =Math.Round(GeographyUtils.CalcDistance(centerLatLng,item.Value),4);
if (distance1 > farDistance)
{
index = item.Key;
farDistance = distance1;
farIsCurTaskPoint = true;
// Message.Show($"调整距离{farDistance}是{farIsCurTaskPoint}的{index}");
}
}
foreach (var item in prevTaskPoint)
{
distance1 = Math.Round(GeographyUtils.CalcDistance(centerLatLng,item.Value),4);
if (distance1 > farDistance)
{
index = item.Key;
farDistance = distance1;
farIsCurTaskPoint = false;
// Message.Show($"调整距离{farDistance}是{farIsCurTaskPoint}的{index}");
}
}
// Message.Show($"最远{farDistance}是{farIsCurTaskPoint}的{index}");
double tempDistance1;
nearDistance = double.MaxValue;
int nearIndex = 0;
if (farIsCurTaskPoint)
{
//最远的航点在当前任务
foreach (var item in prevTaskPoint)
{
tempDistance1 = Math.Round(GeographyUtils.CalcDistance(curTaskPoint[index],item.Value),4);
if (tempDistance1 < nearDistance)
{
nearDistance = tempDistance1;
nearIndex = item.Key;
}
}
//最远的航点在当前任务
// Message.Show($"最远是当前任务{index}距离它最近的前一任务点ind={nearIndex},记录前一任务序号和当前任务位置");
recordLatLng.Add(nearIndex, curTaskPoint[index]);
curTaskPoint.Remove(index);
prevTaskPoint.Remove(nearIndex);
}
else
{
//最远的航点在前一任务
double prevLat = prevTaskPoint[index].Latitude;
double prevLng = prevTaskPoint[index].Longitude;
float prevAlt = prevTaskPoint[index].Altitude;
//最远的航点在当前任务
//Message.Show($"最远点在前一任务ind={index},距离{farDistance}");
foreach (var item in curTaskPoint)
{
tempDistance1 = Math.Round(GeographyUtils.CalcDistance(prevTaskPoint[index],item.Value),4);
if (tempDistance1 < nearDistance)
{
nearDistance = tempDistance1;
nearIndex = item.Key;
}
}
// Message.Show($"最远是前一任务{index}距离它最近的当前任务点ind={nearIndex},记录前一任务序号和当前任务位置");
recordLatLng.Add(index, curTaskPoint[nearIndex]);
curTaskPoint.Remove(nearIndex);
prevTaskPoint.Remove(index);
}
}
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].TargetLat = recordLatLng[i].Latitude;
SelectedTask.SingleCopterInfos[i].TargetLng = recordLatLng[i].Longitude ;
SelectedTask.SingleCopterInfos[i].TargetAlt = recordLatLng[i].Altitude;
}
stopWatch.Stop();
double sumlength = SumFlyLines(Tasks[SelectedTaskIndex - 1].SingleCopterInfos, SelectedTask.SingleCopterInfos);
double Dist;
int crosscount = 0;
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
for (int j = i + 1; j < _copterManager.Copters.Count; j++)
{
Dist = Util.OptimizeRoute.SqureDistanceSegmentToSegment(
new Point3D(Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i].X,
Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i].Y,
Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i].TargetAlt),
new Point3D(Tasks[SelectedTaskIndex].SingleCopterInfos[i].X,
Tasks[SelectedTaskIndex].SingleCopterInfos[i].Y,
Tasks[SelectedTaskIndex].SingleCopterInfos[i].TargetAlt),
new Point3D(Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].X,
Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].Y,
Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j].TargetAlt),
new Point3D(Tasks[SelectedTaskIndex].SingleCopterInfos[j].X,
Tasks[SelectedTaskIndex].SingleCopterInfos[j].Y,
Tasks[SelectedTaskIndex].SingleCopterInfos[j].TargetAlt)
);
//交叉
if (Dist < 0.01)
{
crosscount++;
// Message.Show($"飞机{i}和飞机{j}有交叉,距离{Dist}");
}
}
}
Message.Show($"经纬方式计算用时:{stopWatch.Elapsed.TotalMilliseconds}ms,总飞行距离{sumlength}米,有{crosscount}个交叉");
}
//计算中心点 (三维的)
private PLLocation CenterLatLng(List<PLLocation> point1, List<PLLocation> point2)
{
PLLocation centerLatLng = new PLLocation(0,0,0);
if (point1.Count != point2.Count) return centerLatLng;
double minLat = point1[0].Latitude;
double maxLat = point1[0].Latitude;
double minLng = point1[0].Longitude;
double maxLng = point1[0].Longitude;
double minAlt = point1[0].Altitude;
double maxAlt = point1[0].Altitude;
int count = point1.Count;
for (int i = 0; i < count; i++)
{
minLat = Math.Min(minLat, Math.Min(point1[i].Latitude, point2[i].Latitude));
maxLat = Math.Max(maxLat, Math.Min(point1[i].Latitude, point2[i].Latitude));
minLng = Math.Min(minLng, Math.Min(point1[i].Longitude, point2[i].Longitude));
maxLng = Math.Max(maxLng, Math.Max(point1[i].Longitude, point2[i].Longitude));
minAlt = Math.Min(minAlt, Math.Min(point1[i].Altitude, point2[i].Altitude));
maxAlt = Math.Max(maxAlt, Math.Max(point1[i].Altitude, point2[i].Altitude));
}
centerLatLng.Latitude = (minLat + maxLat) / 2;
centerLatLng.Longitude = (minLng + maxLng) / 2;
centerLatLng.Altitude =(float)(minAlt + maxAlt) / 2;
return centerLatLng;
}
public void OptimizeRoute2()
{
double minLat = SelectedTask.SingleCopterInfos[0].TargetLat;
double maxLat = SelectedTask.SingleCopterInfos[0].TargetLat;
double minLng = SelectedTask.SingleCopterInfos[0].TargetLng;
double maxLng = SelectedTask.SingleCopterInfos[0].TargetLng;
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
var curinfo = SelectedTask.SingleCopterInfos[i];
//recordLatLng.Add(i, new LatLng(curinfo.TargetLat, curinfo.TargetLng));
var lastInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i];
minLat = Math.Min(minLat, Math.Min(curinfo.TargetLat, lastInfo.TargetLat));
maxLat = Math.Max(maxLat, Math.Max(curinfo.TargetLat, lastInfo.TargetLat));
minLng = Math.Min(minLng, Math.Min(curinfo.TargetLng, lastInfo.TargetLng));
maxLng = Math.Max(maxLng, Math.Max(curinfo.TargetLng, lastInfo.TargetLng));
}
double CenterLat = (maxLat + minLat) / 2;
double CenterLng = (maxLng + minLng) / 2;
Message.Show($"中心点:{CenterLat} {CenterLng}");
Dictionary<int, double> distanceDic = new Dictionary<int, double>();
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
var curinfo = SelectedTask.SingleCopterInfos[i];
var lastInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i];
double distance1 = GeographyUtils.CalcDistance(CenterLat, CenterLng, 1,
curinfo.TargetLat, curinfo.TargetLng, 1);
//int[] nums = new int[] { SelectedTaskIndex, i};
int nums = SelectedTaskIndex << 16 ^ i;
distanceDic.Add(nums, distance1);
double distance2 = GeographyUtils.CalcDistance(CenterLat, CenterLng, 1,
lastInfo.TargetLat, lastInfo.TargetLng, 1);
nums = (SelectedTaskIndex - 1) << 16 ^ i;
distanceDic.Add(nums, distance2);
}
distanceDic = distanceDic.OrderByDescending(o => o.Value).ToDictionary(p => p.Key, o => o.Value);
Dictionary<int, LatLng> recordLatLng = new Dictionary<int, LatLng>();
while (distanceDic.Count > 0)
{
KeyValuePair<int, double> kv = distanceDic.First();
int taskIndex = kv.Key >> 16;
int copterID = kv.Key & 0xffff;
var curInfo = Tasks[taskIndex].SingleCopterInfos[copterID];
if (taskIndex == SelectedTaskIndex)
{
double mindistance = double.MaxValue;
int index = 0;
for (int i = 0; i < Tasks[taskIndex - 1].SingleCopterInfos.Count; i++)
{
if (distanceDic.ContainsKey((taskIndex - 1) << 16 ^ i))
{
var destInfo = Tasks[taskIndex - 1].SingleCopterInfos[i];
double distance = GeographyUtils.CalcDistance(curInfo.TargetLat, curInfo.TargetLng, 1,
destInfo.TargetLat, destInfo.TargetLng, 1);
if (distance < mindistance)
{
mindistance = distance;
index = i;
}
}
}
recordLatLng.Add(index,
new LatLng(SelectedTask.SingleCopterInfos[copterID].TargetLat,
SelectedTask.SingleCopterInfos[copterID].TargetLng));
Message.Show($"航点{taskIndex} ID{copterID + 1} --航点{taskIndex - 1} id{index + 1}");
distanceDic.Remove(kv.Key);
distanceDic.Remove(( taskIndex - 1) << 16 ^ index );
}
else
{
double mindistance = double.MaxValue;
int index = 0;
for (int i = 0; i < Tasks[taskIndex + 1].SingleCopterInfos.Count; i++)
{
if (distanceDic.ContainsKey((taskIndex + 1) << 16 ^ i))
{
var destInfo = Tasks[taskIndex + 1].SingleCopterInfos[i];
double distance = GeographyUtils.CalcDistance(curInfo.TargetLat, curInfo.TargetLng, 1,
destInfo.TargetLat, destInfo.TargetLng, 1);
if (distance < mindistance && distanceDic.ContainsKey((SelectedTaskIndex) << 16 ^ i))
{
mindistance = distance;
index = i;
}
}
}
recordLatLng.Add(copterID,
new LatLng(SelectedTask.SingleCopterInfos[index].TargetLat,
SelectedTask.SingleCopterInfos[index].TargetLng));
Message.Show($"航点{taskIndex} ID{copterID + 1} --航点{taskIndex + 1} id{index + 1}");
distanceDic.Remove(kv.Key);
distanceDic.Remove(( taskIndex + 1) << 16 ^ index );
}
}
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
SelectedTask.SingleCopterInfos[i].TargetLat = recordLatLng[i].Lat;
SelectedTask.SingleCopterInfos[i].TargetLng = recordLatLng[i].Lng;
}
}
public void OptimizeRoute()
{
Dictionary<int[], double> distanceDic = new Dictionary<int[], double>();
Dictionary<int, LatLng> recordLatLng = new Dictionary<int, LatLng>();
for (int i = 0; i < SelectedTask.SingleCopterInfos.Count; i++)
{
var curinfo = SelectedTask.SingleCopterInfos[i];
recordLatLng.Add(i, new LatLng(curinfo.TargetLat, curinfo.TargetLng));
for (int j = 0; j < Tasks[SelectedTaskIndex - 1].SingleCopterInfos.Count; j++)
{
var lastInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[j];
double distance = GeographyUtils.CalcDistance(curinfo.TargetLat, curinfo.TargetLng, curinfo.TargetLng,
lastInfo.TargetLat, lastInfo.TargetLng, lastInfo.TargetLng);
int[] nums = new int[] {i,j};
distanceDic.Add(nums, distance);
}
}
distanceDic = distanceDic.OrderBy(o=>o.Value).ToDictionary(p=>p.Key,o=>o.Value);
List<int> movedCopters = new List<int>();
List<int> usedPoints = new List<int>();
foreach (KeyValuePair <int[], double> kv in distanceDic)
{
int moveCopterNum = kv.Key[1];
int destNum = kv.Key[0];
if (movedCopters.Contains(moveCopterNum) || usedPoints.Contains(destNum))
continue;
SelectedTask.SingleCopterInfos[moveCopterNum].TargetLat = recordLatLng[destNum].Lat;
SelectedTask.SingleCopterInfos[moveCopterNum].TargetLng = recordLatLng[destNum].Lng;
movedCopters.Add(moveCopterNum);
usedPoints.Add(destNum);
}
}
public void ImportWaypoint(string tasksText)
{
dynamic jsonfile = JsonConvert.DeserializeObject(tasksText);
dynamic points = jsonfile.points;
for (int i = 0; i < SelectedTask.SingleCopterInfos.Count; i++)
{
MapManager _mapManager = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<MapManager>();
var pointjson= points[i];
System.Windows.Point point = new System.Windows.Point((int)pointjson.x, (int)pointjson.y);
var loc = _mapManager.MapView.gmap.FromLocalToLatLng((int)point.X , (int)point.Y);
SelectedTask.SingleCopterInfos[i].TargetLat = loc.Lat;
SelectedTask.SingleCopterInfos[i].TargetLng = loc.Lng;
}
}
// 导入任务
public void ImportTasks(dynamic tasks, bool isMeter)
{
var copters = _copterManager.Copters;
if (Tasks.Count == 0)
AddTakeOffTask(copters);
foreach (var task in tasks)
{
switch ((FlightTaskType)task.type)
{
case FlightTaskType.TakeOff:
// AddTakeOffTask(copters); // added by ZJF
// TakeOffNumAttr = task.takeoffnumber;
RestoreTakeOffTask((byte)task.takeoffTime, task.singleCopterInfos);
break;
case FlightTaskType.FlyTo:
RestoreFlyToTask((bool)task.staggerRoutes, (int)task.flytoTime, (int)task.loiterTime, (string)task.taskname, task.singleCopterInfos, isMeter);
break;
case FlightTaskType.Land:
RestoreLandTask(task.singleCopterInfos);
break;
}
}
}
// private void ImportCoptersLocate(dynamic coptersLocate)
// {
//
// }
private void ImportGroupsInfo(dynamic coptersLocate)
{
}
public void SelectTask(int taskIndex)
{
if (taskIndex == -1) return;
this.SelectedTaskIndex = taskIndex;
this.SelectedTask = Tasks[taskIndex];
}
/**
* 在悬停任务时右键waypoint为取消选中
*/
public void RightSelect(int taskIndex, ICopter copter)
{
this.SelectedTaskIndex = taskIndex;
this.SelectedTask = Tasks[taskIndex];
}
private int Name2Index(string name) // 获取指定copter名字对应的序号
{
int index = -1;
for (int i = 0; i < SelectedTask.SingleCopterInfos.Count; i++)
{
if (name.Equals(SelectedTask.SingleCopterInfos[i].Copter.Name))
{
return i;
}
}
return index;
}
private string DeleteSelectedName( string nameArray, string name ) // 删除字符串中的指定项
{
string copterStr = nameArray;
if (copterStr.Equals(""))
return "";
string[] copterNameArray = copterStr.Split(',');
copterNameArray = copterNameArray.Where(str => !str.Equals(name)).ToArray();
copterStr = "";
for (int i = 0; i < copterNameArray.Length; i++)
{
copterStr = copterStr + copterNameArray[i];
if (i < (copterNameArray.Length - 1))
{
copterStr = copterStr + ",";
}
}
return copterStr;
}
//左键选中任务
public void Select(FlightTask flightTask)
{
this.SelectedTaskIndex = Tasks.IndexOf(flightTask);
this.SelectedTask = flightTask;
}
// 右键选中任务
public void RightSelect(FlightTask flightTask)
{
int RightSelectedTaskIndexTmp = Tasks.IndexOf(flightTask);
if (this.RightSelectedTaskIndex == RightSelectedTaskIndexTmp)
{
this.RightSelectedTaskIndex = -RightSelectedTaskIndexTmp;
}
else
{
this.RightSelectedTaskIndex = RightSelectedTaskIndexTmp;
}
}
#region Run and pause.
private bool? _IsPaused;
public bool? IsPaused
{
get { return _IsPaused; }
private set {
if (Set(nameof(IsPaused), ref _IsPaused, value))
{
if (_IsPaused??false)
{
MessageText = "任务暂停!";
}else
{
MessageText = "任务运行中";
}
}
}
}
TimeSpan timeSpan;
DateTime taskStartTime;
public async Task RunTaskAsync()
{
if (Tasks.Count == 0) return;
if (CurrentRunningTaskIndex == 0)
{
taskStartTime = DateTime.Now;
Message.Show($"{DateTime.Now.ToString("HH:mm:ss")}:任务开始");
}
await RunAsync();
if ((IsPaused ?? false) == false)
{
timeSpan = DateTime.Now - taskStartTime;
Message.Show($"{DateTime.Now.ToString("HH:mm:ss")}:任务结束");
Message.Show($"总时长 = {timeSpan.Minutes}分{timeSpan.Seconds}秒");
}
}
public async Task RunAsync()
{
IsPaused = false;
for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++)
{
var task = Tasks[i];
//task.Status目前只用于任务条下面状态显示不同颜色
task.Status = FlightTaskStatus.Stop;
}
AppEx.Current.AppMode = AppMode.RunningTasks;
StartAvoidingCrash(); //开始碰撞检测
TaskState = TasksStatus.Running;
for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++)
{
var task = Tasks[i];
//task.Status目前只用于任务条下面状态显示不同颜色
task.Status = FlightTaskStatus.Running;
CurrentRunningTask = task;
CurrentRunningTaskIndex = i;
//////////////////显示提示信息
int starttime = 0;
for (int j = 0; j < task.TaskIndex; j++)
starttime += GetTaskTime(j);
TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(starttime));
Message.Show($"{ts}:任务{i+1} {task.TaskCnName } 开始执行,需{ GetTaskTime(task.TaskIndex)}秒");
/////////////////////////
await task.RunAsync().ConfigureAwait(false);
// 1. 被暂停时,中断 RunAsync。继续运行时将把此时运行了一半的 CurrentRunningTask 重新运行一遍。
if (IsPaused == true)
{
task.Status = FlightTaskStatus.Paused;
TaskState = TasksStatus.Paused;
Message.Show($"任务{i + 1} {task.TaskCnName } 暂停执行");
return;
}
task.Status = FlightTaskStatus.Stop;
}
// 2. 正常结束时,重置 CurrentRunningTask、CurrentRunningTaskIndex 和 IsPaused。
TaskState = TasksStatus.Stop;
CurrentRunningTask = null;
CurrentRunningTaskIndex = 0;
IsPaused = null;
}
public void Pause()
{
IsPaused = true;
}
#endregion Run and pause.
Dictionary<int, string> AvoidCrashLog = new Dictionary<int, string >();
private async void StartAvoidingCrash()
{
await Task.Factory.StartNew(AvoidCrashtoshow);
await Task.Factory.StartNew(LoopToAvoidCrash);
}
private async void AvoidCrashtoshow()
{
while (IsPaused == false)
{
try
{
foreach (KeyValuePair<int, string> kv in AvoidCrashLog)
{
string moveCopterNum = kv.Value;
int destNum = kv.Key;
Message.Show(moveCopterNum);
}
AvoidCrashLog.Clear(); //可能有丢失
}
catch // 林俊清, 20151102, 通常是“集合已修改”异常。
{
}
finally
{
await Task.Delay(100).ConfigureAwait(false);
}
}
}
private async void LoopToAvoidCrash()
{
while (IsPaused == false)
{
try
{
double distance;
foreach (var copter in _copterManager.Copters)
{
foreach (var anotherCopter in _copterManager.Copters)
{
if (copter != anotherCopter && copter.IsTooCloseTo(anotherCopter, out distance))
{
//防止卡顿,单加任务来显示
AvoidCrashLog.Add(1, $"{copter.Name} 与 {anotherCopter.Name} 距离过近,间距{distance}米。");
}
}
}
}
catch // 林俊清, 20151102, 通常是“集合已修改”异常。
{
}
finally
{
await Task.Delay(50).ConfigureAwait(false);
}
}
}
private void LoadIni()
{
Windows.IniHelper.IniFiles inifilse = new Windows.IniHelper.IniFiles();
string readvalue = "";
int intTemp;
float floatTemp;
readvalue = inifilse.IniReadvalue("Default", "ColumnCount");
if (readvalue!= "" && int.TryParse(readvalue,out intTemp))
ColumnCount = int.Parse(readvalue);
readvalue = inifilse.IniReadvalue("Default", "ColumnDistance");
if (readvalue != "" && float.TryParse(readvalue, out floatTemp))
ColumnDistance = float.Parse(readvalue);
readvalue = inifilse.IniReadvalue("Default", "RowDistance");
if (readvalue != "" && float.TryParse(readvalue, out floatTemp))
RowDistance = float.Parse(readvalue);
readvalue = inifilse.IniReadvalue("Default", "Orientation");
if (readvalue != "" && int.TryParse(readvalue, out intTemp))
Orientation = int.Parse(readvalue);
}
public void SaveIni()
{
Windows.IniHelper.IniFiles inifilse = new Windows.IniHelper.IniFiles();
inifilse.IniWritevalue("Default", "ColumnCount", ColumnCount.ToString());
inifilse.IniWritevalue("Default", "ColumnDistance", ColumnDistance.ToString());
inifilse.IniWritevalue("Default", "RowDistance", RowDistance.ToString());
inifilse.IniWritevalue("Default", "Orientation", Orientation.ToString());
}
}
public class FlightTaskAddedEventArgs : EventArgs
{
public FlightTask LastTask { get; set; }
public FlightTask AddedTask { get; set; }
}
public class FlightTaskDeledEventArgs : EventArgs
{
public FlightTask DeledTask { get; set; }
public int TaskIndex { get; set; }
}
public class FlightTaskTypeChangedEventArgs : EventArgs
{
public FlightTaskTypeChangedEventArgs(FlightTask changedFlightTask)
{
this.ChangedFlightTask = changedFlightTask;
}
public FlightTask ChangedFlightTask { get; set; }
}
public class FlightTaskcnNameChangedEventArgs : EventArgs
{
public FlightTaskcnNameChangedEventArgs(FlightTask changedFlightTask)
{
this.ChangedFlightTask = changedFlightTask;
}
public FlightTask ChangedFlightTask { get; set; }
}
public class FlightTaskAddedOriginalEventArgs : EventArgs
{
public double Lat { get; set; }
public double Lng { get; set; }
}
public class SingleCopterInfoChangedEventArgs : EventArgs
{
public SingleCopterInfoChangedEventArgs(FlightTaskSingleCopterInfo changedSingleCopterInfo)
{
this.ChangedSingleCopterInfo = changedSingleCopterInfo;
}
public FlightTaskSingleCopterInfo ChangedSingleCopterInfo { get; set; }
}
}