[Extensions.cs]碰撞判断逻辑改了一下 [FlightTaskManager.cs]任务开始前加了预检测,RTK没fix或GPS没有收到8颗以上卫星 [FlightTask_FlyTo.cs]清理飞往逻辑,优化通讯 [FlightTask_ReturnToLand.cs]加入MissionStatus控制 【FlightTask_TakeOff.cs】加入MissionStatus控制 【ControlPanelViewModel.cs】加入批量修改参数功能 [ControlPanelView.xaml]加入批量修改参数功能 [MapView_CopterDrawing.cs]MissionStatus显示,在现有飞机上加个小头
449 lines
18 KiB
C#
449 lines
18 KiB
C#
using Plane.Collections;
|
|
using Plane.Copters;
|
|
using Plane.FormationCreator.Formation;
|
|
using Plane.Logging;
|
|
using Microsoft.Maps.MapControl.WPF;
|
|
using Microsoft.Practices.ServiceLocation;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Effects;
|
|
using System.Windows.Shapes;
|
|
|
|
namespace Plane.FormationCreator.Views
|
|
{
|
|
public partial class MapView
|
|
{
|
|
private class CopterDrawing
|
|
{
|
|
public CopterDrawing(ICopter copter, Map map)
|
|
{
|
|
this.Copter = copter;
|
|
_map = map;
|
|
if (copter is Copter)
|
|
{
|
|
_brush = ((Copter)copter).Brush;
|
|
_color = ((SolidColorBrush)_brush).Color;
|
|
}
|
|
else
|
|
{
|
|
_color = _colors[(_colorIndex++ % _colors.Length)];
|
|
_brush = new SolidColorBrush(_color);
|
|
}
|
|
|
|
_flightTaskManager.TasksCleared += (sender, e) =>
|
|
{
|
|
for (int i = this.Route.Locations.Count - 1; i >= 1; i--)
|
|
{
|
|
this.Route.Locations.RemoveAt(i);
|
|
}
|
|
foreach (var wp in this.Waypoints)
|
|
{
|
|
_map.Children.Remove(wp);
|
|
}
|
|
this.Waypoints.Clear();
|
|
};
|
|
}
|
|
|
|
static DropShadowEffect _selectedEffect = new DropShadowEffect();
|
|
|
|
static SolidColorBrush _selectedTaskStroke = new SolidColorBrush(Colors.White);
|
|
|
|
static Color[] _colors = new Color[]
|
|
{
|
|
Color.FromArgb(180, 255, 0, 0),
|
|
Color.FromArgb(180, 235, 97, 0),
|
|
Color.FromArgb(180, 255, 255, 0),
|
|
Color.FromArgb(180, 0, 255, 0),
|
|
Color.FromArgb(180, 0, 198, 255),
|
|
Color.FromArgb(180, 0, 122, 204),
|
|
Color.FromArgb(180, 174, 0, 255)
|
|
};
|
|
|
|
static int _colorIndex = 0;
|
|
|
|
const double COPTER_RADIUS = 12;
|
|
const double WAYPOINT_RADIUS = 6;
|
|
|
|
public ICopter Copter { get; set; }
|
|
public Grid DotContainer { get; set; }
|
|
public Polygon Dot { get; set; }
|
|
public MapPolyline Track { get; set; }
|
|
public Location LastLocation { get; set; }
|
|
|
|
public MapPolyline Route { get; set; }
|
|
public List<Ellipse> Waypoints { get; set; } = new List<Ellipse>();
|
|
|
|
Map _map;
|
|
Color _color;
|
|
Brush _brush;
|
|
|
|
ILogger _logger = ServiceLocator.Current.GetInstance<ILogger>();
|
|
CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
|
|
FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
|
|
|
|
public void AddOrMoveCopter()
|
|
{
|
|
try
|
|
{
|
|
var location = new Location(Copter.Latitude, Copter.Longitude, Copter.Altitude);
|
|
Point center = _map.LocationToViewportPoint(location);
|
|
bool locationUpdated = true;
|
|
SolidColorBrush blackBrush = new SolidColorBrush();
|
|
if (this.Dot == null)
|
|
{
|
|
Track = new MapPolyline();
|
|
Track.Stroke = _brush;
|
|
Track.StrokeThickness = 3.0;
|
|
Track.Locations = new LocationCollection();
|
|
|
|
//实时飞行航线
|
|
// _map.Children.Add(Track);
|
|
|
|
//画三角形飞机
|
|
Dot = new Polygon();
|
|
// (0,-12)(-8,12)(8,12)是个倒三角形
|
|
//
|
|
//
|
|
|
|
|
|
|
|
Dot.Points.Add(new Point(0, -COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(-COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
|
|
|
|
|
|
Dot.Fill = _brush; // new SolidColorBrush(Color.FromArgb(200, 0, 122, 204));
|
|
Dot.StrokeThickness = 1;
|
|
Dot.Width = COPTER_RADIUS * 2;
|
|
Dot.Height = COPTER_RADIUS * 2;
|
|
ToolTip tt = new ToolTip();
|
|
tt.Content = $"Name: {Copter.Name}, Location: {location}";
|
|
Dot.ToolTip = tt;
|
|
|
|
DotContainer = new Grid { Tag = COPTER_TAG };
|
|
DotContainer.Children.Add(Dot);
|
|
//飞机里面的编号
|
|
DotContainer.Children.Add(new TextBlock
|
|
{
|
|
Text = Copter.Name,
|
|
Foreground = new SolidColorBrush(Colors.White),
|
|
Margin = new Thickness(-COPTER_RADIUS * 2, -COPTER_RADIUS * 1.5, 0, 0),
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center
|
|
});
|
|
|
|
//飞机加入地图
|
|
_map.Children.Add(DotContainer);
|
|
|
|
|
|
MapLayer.SetZIndex(DotContainer, 100);
|
|
|
|
this.Route = new MapPolyline { Locations = new LocationCollection { location } };
|
|
this.Route.Stroke = _brush;
|
|
this.Route.StrokeThickness = 2.0;
|
|
//显示计划航线
|
|
|
|
// _map.Children.Add(this.Route);
|
|
|
|
|
|
|
|
this.LastLocation = location;
|
|
|
|
RegisterEventHandlersForDraggingCopter(DotContainer);
|
|
}
|
|
else
|
|
{
|
|
Dot.Points.Clear();
|
|
if (Copter.MissionStatus == 1)
|
|
{
|
|
Dot.Points.Add(new Point(-4, -COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(0, -COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(-COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
}
|
|
else {
|
|
|
|
Dot.Points.Add(new Point(0, -COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(-COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
Dot.Points.Add(new Point(COPTER_RADIUS * 2 / 3, COPTER_RADIUS));
|
|
}
|
|
|
|
|
|
|
|
if (LastLocation != null && location.CalcDistance(LastLocation) < 0.1)
|
|
{
|
|
locationUpdated = false;
|
|
}
|
|
if (locationUpdated)
|
|
{
|
|
//dot.RenderTransform = new RotateTransform(GeographyUtils.CalcDirection2D(lastLocation.Latitude, lastLocation.Longitude, location.Latitude, location.Longitude).RadiansToDegrees());
|
|
(Dot.ToolTip as ToolTip).Content = $"Name: {Copter.Name}, Location: {location}";
|
|
}
|
|
}
|
|
|
|
if (Copter.GetShowLEDAsync())
|
|
blackBrush.Color = Colors.White;
|
|
else
|
|
blackBrush.Color = Colors.Transparent;
|
|
|
|
|
|
|
|
|
|
Dot.Stroke = blackBrush;
|
|
|
|
var trans = Dot.RenderTransform as RotateTransform;
|
|
if (trans == null)
|
|
{
|
|
Dot.RenderTransform = new RotateTransform(Copter.Heading);
|
|
}
|
|
else
|
|
{
|
|
if (trans.Angle != Copter.Heading)
|
|
{
|
|
trans.Angle = Copter.Heading;
|
|
}
|
|
}
|
|
|
|
if (locationUpdated)
|
|
{
|
|
Track.Locations.Add(location);
|
|
this.Route.Locations[0] = location;
|
|
MapLayer.SetPosition(Dot.Parent, location);
|
|
this.LastLocation = location;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Log(ex);
|
|
}
|
|
}
|
|
|
|
public void AddWaypoint(Location location, FlightTaskType type)
|
|
{
|
|
// Add waypoint.
|
|
var wp = new Ellipse
|
|
{
|
|
Tag = WAYPOINT_TAG,
|
|
Fill = _brush,
|
|
StrokeThickness = 2,
|
|
Width = WAYPOINT_RADIUS * 2,
|
|
Height = WAYPOINT_RADIUS * 2
|
|
}; ;
|
|
Waypoints.Add(wp);
|
|
_map.Children.Add(wp);
|
|
MapLayer.SetZIndex(wp, 100);
|
|
var wpPos = _map.LocationToViewportPoint(location);
|
|
wpPos.X -= WAYPOINT_RADIUS;
|
|
wpPos.Y -= WAYPOINT_RADIUS;
|
|
MapLayer.SetPosition(wp, _map.ViewportPointToLocation(wpPos));
|
|
|
|
SetEffect(_copterManager.SelectedCopters.Contains(Copter));
|
|
|
|
// Add route point.
|
|
Route.Locations.Add(location);
|
|
|
|
// Register event handlers.
|
|
RegisterEventHandlersForDraggingWaypoint(wp, taskIndex: Waypoints.Count);
|
|
|
|
// Register event handlers for task info.
|
|
RegisterEventHandlersForTaskInfo(wp, taskIndex: Waypoints.Count);
|
|
}
|
|
|
|
private void RegisterEventHandlersForDraggingCopter(Grid copterElement)
|
|
{
|
|
var dragMoving = false;
|
|
double offsetX = 0;
|
|
double offsetY = 0;
|
|
copterElement.MouseLeftButtonDown += (sender, e) =>
|
|
{
|
|
_copterManager.Select(this.Copter);
|
|
if (Copter is FakeCopter)
|
|
{
|
|
var posInObject = e.GetPosition(copterElement);
|
|
offsetX = posInObject.X;
|
|
offsetY = posInObject.Y;
|
|
|
|
dragMoving = true;
|
|
}
|
|
};
|
|
_map.MouseMove += (sender, e) =>
|
|
{
|
|
if (dragMoving)
|
|
{
|
|
var pos = e.GetPosition(_map);
|
|
pos.X -= offsetX;
|
|
pos.Y -= offsetY;
|
|
MapLayer.SetPosition(copterElement, _map.ViewportPointToLocation(pos));
|
|
|
|
var center = _map.ViewportPointToLocation(pos);
|
|
|
|
var routePoint = this.Route.Locations[0];
|
|
routePoint.Latitude = center.Latitude;
|
|
routePoint.Longitude = center.Longitude;
|
|
|
|
var fc = Copter as FakeCopter;
|
|
fc.SetProperties(
|
|
latitude: center.Latitude,
|
|
longitude: center.Longitude
|
|
);
|
|
}
|
|
};
|
|
_map.MouseLeftButtonUp += (sender, e) =>
|
|
{
|
|
if (dragMoving) dragMoving = false;
|
|
};
|
|
}
|
|
|
|
private Dictionary<object, bool> _dictDraggingWp = new Dictionary<object, bool>();
|
|
private void RegisterEventHandlersForDraggingWaypoint(Ellipse wp, int taskIndex)
|
|
{
|
|
_dictDraggingWp[wp] = false;
|
|
double offsetX = 0;
|
|
double offsetY = 0;
|
|
wp.MouseLeftButtonDown += (sender, e) =>
|
|
{
|
|
_copterManager.Select(this.Copter);
|
|
_flightTaskManager.Select(taskIndex, this.Copter);
|
|
var posInObject = e.GetPosition(wp);
|
|
offsetX = posInObject.X;
|
|
offsetY = posInObject.Y;
|
|
|
|
_dictDraggingWp[wp] = true;
|
|
};
|
|
wp.MouseRightButtonDown += (sender, e) =>
|
|
{
|
|
_flightTaskManager.RightSelect(taskIndex, this.Copter);
|
|
};
|
|
_map.MouseMove += (sender, e) =>
|
|
{
|
|
if (_dictDraggingWp[wp])
|
|
{
|
|
var eventPos = e.GetPosition(_map);
|
|
var leftTopPos = new Point(eventPos.X - offsetX, eventPos.Y - offsetY);
|
|
MapLayer.SetPosition(wp, _map.ViewportPointToLocation(leftTopPos));
|
|
|
|
var centerPos = new Point(leftTopPos.X + WAYPOINT_RADIUS, leftTopPos.Y + WAYPOINT_RADIUS);
|
|
var centerLoc = _map.ViewportPointToLocation(centerPos);
|
|
var routePoint = this.Route.Locations[taskIndex];
|
|
var modifyingSingleCopterInfo = _flightTaskManager.SelectedTask.SingleCopterInfos.Find(i => i.Copter == Copter);
|
|
modifyingSingleCopterInfo.TargetLat = routePoint.Latitude = centerLoc.Latitude;
|
|
modifyingSingleCopterInfo.TargetLng = routePoint.Longitude = centerLoc.Longitude;
|
|
}
|
|
};
|
|
_map.MouseLeftButtonUp += (sender, e) =>
|
|
{
|
|
if (_dictDraggingWp[wp]) _dictDraggingWp[wp] = false;
|
|
};
|
|
}
|
|
|
|
private void RegisterEventHandlersForTaskInfo(Ellipse wp, int taskIndex)
|
|
{
|
|
var info = _flightTaskManager.Tasks[taskIndex].SingleCopterInfos.FirstOrDefault(i => i.Copter == this.Copter);
|
|
info.PropertyChanged += (sender, e) =>
|
|
{
|
|
switch (e.PropertyName)
|
|
{
|
|
case nameof(FlightTaskSingleCopterInfo.TargetLat):
|
|
case nameof(FlightTaskSingleCopterInfo.TargetLng):
|
|
case nameof(FlightTaskSingleCopterInfo.TargetAlt):
|
|
if (!_dictDraggingWp.GetValue(wp, false))
|
|
{
|
|
var centerLocation = new Location(info.TargetLat, info.TargetLng, info.TargetAlt);
|
|
var centerPos = _map.LocationToViewportPoint(centerLocation);
|
|
var leftTopPos = new Point(centerPos.X - WAYPOINT_RADIUS, centerPos.Y - WAYPOINT_RADIUS);
|
|
MapLayer.SetPosition(wp, _map.ViewportPointToLocation(leftTopPos));
|
|
var routePoint = Route.Locations[taskIndex];
|
|
routePoint.Latitude = info.TargetLat;
|
|
routePoint.Longitude = info.TargetLng;
|
|
routePoint.Altitude = info.TargetAlt;
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
|
|
public void RemoveCopter()
|
|
{
|
|
_map.Children.Remove(this.DotContainer);
|
|
_map.Children.Remove(this.Track);
|
|
_map.Children.Remove(this.Route);
|
|
foreach (var item in this.Waypoints)
|
|
{
|
|
_map.Children.Remove(item);
|
|
}
|
|
}
|
|
|
|
public void SetShowroute(bool? showroute)
|
|
{
|
|
|
|
if (showroute ?? false )
|
|
_map.Children.Add(this.Route);
|
|
else
|
|
_map.Children.Remove(this.Route);
|
|
}
|
|
|
|
public void SetShowtrack(bool? showtrack)
|
|
{
|
|
if (showtrack ?? false)
|
|
_map.Children.Add(Track);
|
|
else
|
|
_map.Children.Remove(Track);
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetEffect(bool selected)
|
|
{
|
|
Dot.Effect = selected ? _selectedEffect : null;
|
|
Waypoints.ForEach(wp => wp.Effect = Dot.Effect);
|
|
}
|
|
|
|
public void SetTaskEffect(int taskIndex)
|
|
{
|
|
var wpIndex = taskIndex - 1; // Waypoints 中没有起飞点。
|
|
if (wpIndex >= 0 && wpIndex < Waypoints.Count)
|
|
{
|
|
Waypoints.ForEach(p => p.Stroke = null);
|
|
var wp = Waypoints[wpIndex];
|
|
wp.Stroke = _selectedTaskStroke;
|
|
}
|
|
}
|
|
|
|
// 右击任务时触发
|
|
public void SetTaskRightEffect(int taskIndex, bool flag)
|
|
{
|
|
var wpIndex = taskIndex - 1; // Waypoints 中没有起飞点。
|
|
if (wpIndex >= 0 && wpIndex < Waypoints.Count)
|
|
{
|
|
// Waypoints.ForEach(p => p.Stroke = null);
|
|
var wp = Waypoints[wpIndex];
|
|
// Route.Locations.RemoveAt(wpIndex);
|
|
// Route.Visibility = Visibility.Hidden;
|
|
// wp.Stroke = _selectedTaskStroke;
|
|
// var flightTaskTmp = _flightTaskManager.Tasks[taskIndex];
|
|
if (!flag)
|
|
{
|
|
wp.Visibility = Visibility.Hidden;
|
|
//Route.Visibility = Visibility.Hidden;
|
|
//Route.Children.RemoveAt(1);
|
|
}
|
|
else
|
|
{
|
|
wp.Visibility = Visibility.Visible;
|
|
//Route.Visibility = Visibility.Visible;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|