520 lines
19 KiB
C#
520 lines
19 KiB
C#
using Plane.Copters;
|
||
using Plane;
|
||
using Plane.FormationCreator.Formation;
|
||
using Plane.Logging;
|
||
using Microsoft.Win32;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.Specialized;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics;
|
||
using System.Linq;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Data;
|
||
using System.Windows.Documents;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using System.Windows.Media.Imaging;
|
||
using System.Windows.Navigation;
|
||
using System.Windows.Shapes;
|
||
using Plane.Collections;
|
||
using Microsoft.Maps.MapControl.WPF;
|
||
using Microsoft.Maps.MapControl.WPF.Overlays;
|
||
using System.Windows.Media.Effects;
|
||
using Microsoft.Practices.ServiceLocation;
|
||
using Plane.FormationCreator.ViewModels;
|
||
using Plane.Geography;
|
||
using Plane.FormationCreator.Maps;
|
||
using Plane.Windows.Messages;
|
||
|
||
namespace Plane.FormationCreator.Views
|
||
{
|
||
/// <summary>
|
||
/// Interaction logic for MapView.xaml
|
||
/// </summary>
|
||
public partial class MapView : UserControl
|
||
{
|
||
public MapView()
|
||
{
|
||
InitializeComponent();
|
||
|
||
this.DataContext = ServiceLocator.Current.GetInstance<MapViewModel>();
|
||
|
||
_mapManager.MapView = this;
|
||
_mapManager.SetCenterGetter(() => new LatLng { Lat = map.Center.Latitude, Lng = map.Center.Longitude });
|
||
|
||
_flightTaskManager.TaskAdded += FlightTaskManager_TaskAdded;
|
||
_flightTaskManager.OnOriginalSet += FlightTaskManager_SetOriginal;
|
||
|
||
Task.Factory.StartNew(async () =>
|
||
{
|
||
int delay = 500;
|
||
while (true)
|
||
{
|
||
if (Dispatcher.Invoke(RemoveLoadingErrorMessage))
|
||
{
|
||
delay = 2000;
|
||
}
|
||
await Task.Delay(delay);
|
||
}
|
||
});
|
||
|
||
_copterManager.SelectedCoptersChanged += (sender, e) =>
|
||
{
|
||
//if (AppEx.Instance.CurrentMode.IsForTasks())
|
||
//{
|
||
e.RemovedCopters?.ForEach(copter => _copterDrawings.GetValue(copter)?.SetEffect(false));
|
||
e.AddedCopters?.ForEach(copter => _copterDrawings.GetValue(copter)?.SetEffect(true));
|
||
//}
|
||
};
|
||
|
||
_flightTaskManager.PropertyChanged += (sender, e) =>
|
||
{
|
||
switch (e.PropertyName)
|
||
{
|
||
case nameof(FlightTaskManager.SelectedTaskIndex):
|
||
foreach (var item in _copterDrawings)
|
||
{
|
||
var copterDrawing = item.Value;
|
||
copterDrawing.SetTaskEffect(_flightTaskManager.SelectedTaskIndex);
|
||
}
|
||
break;
|
||
case nameof(FlightTaskManager.RightSelectedTaskIndex): // 单击右键触发
|
||
int taskIndexTmp = Math.Abs(_flightTaskManager.RightSelectedTaskIndex);
|
||
foreach (var item in _copterDrawings)
|
||
{
|
||
var copterDrawing = item.Value;
|
||
copterDrawing.SetTaskRightEffect(taskIndexTmp,
|
||
_flightTaskManager.Tasks[taskIndexTmp].IsRightSelected);
|
||
}
|
||
_flightTaskManager.Tasks[taskIndexTmp].IsRightSelected = !_flightTaskManager.Tasks[taskIndexTmp].IsRightSelected;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
};
|
||
|
||
map.MouseLeftButtonDown += (sender, e) =>
|
||
{
|
||
if (IsMouseOnCopterOrWaypoint(e.OriginalSource))
|
||
{
|
||
e.Handled = true;
|
||
}
|
||
};
|
||
|
||
_copterManager.Copters.ForEach(copter => copter.LocationChanged += Copter_LocationChanged);
|
||
_copterManager.Copters.CollectionChanged += Copters_CollectionChanged;
|
||
|
||
//_copterManager.Copters.ForEach(copter => AddOrMoveCopterForModifyingTask(copter));
|
||
//_copterManager.Copters.CollectionChanged += CoptersForModifyingTask_CollectionChanged;
|
||
|
||
map.MouseDoubleClick += async (sender, e) =>
|
||
{
|
||
e.Handled = true;
|
||
|
||
//// Test
|
||
//var pos = map.ViewportPointToLocation(e.GetPosition(map));
|
||
//AddOrMoveCopter(new FakeCopter(pos.Latitude, pos.Longitude));
|
||
|
||
// 林俊清, 20150930, AppMode 存在意义已不大;只有正在运行任务的时候才不允许指点。
|
||
//if (AppEx.Current.AppMode != AppMode.ControllingCopters) return;
|
||
if (_flightTaskManager.IsPaused == false) return;
|
||
|
||
var copters = _copterManager.AcceptingControlCopters;
|
||
|
||
if (!copters.Any()) return;
|
||
|
||
var pos = map.ViewportPointToLocation(e.GetPosition(map));
|
||
var centerLat = copters.Average(c => c.Latitude);
|
||
var centerLng = copters.Average(c => c.Longitude);
|
||
var latDelta = pos.Latitude - centerLat;
|
||
var lngDelta = pos.Longitude - centerLng;
|
||
|
||
|
||
await Task.WhenAll(copters.Select(copter => copter.FlyToAsync(copter.Latitude + latDelta, copter.Longitude + lngDelta, copter.Altitude)));
|
||
};
|
||
|
||
var center = _appConfig.Center;
|
||
map.Center = new Location(center.Lat, center.Lng);
|
||
map.ZoomLevel = _appConfig.ZoomLevel;
|
||
|
||
|
||
map.ViewChangeOnFrame += (object sender, MapEventArgs e) =>
|
||
{
|
||
if ( map.Mode.GetType().ToString() == "Microsoft.Maps.MapControl.WPF.AerialMode")
|
||
if (map.ZoomLevel >19)
|
||
map.ZoomLevel = 19;
|
||
};
|
||
|
||
Rectangle rectangle = new Rectangle();
|
||
bool drawRectangle = false;
|
||
Point startPosition = new Point();
|
||
Point leftTopPoint = new Point();
|
||
map.MouseRightButtonDown += (sender, e) =>
|
||
{
|
||
rectangle = new Rectangle();
|
||
rectangle.Width = 0;
|
||
rectangle.Height = 0;
|
||
rectangle.StrokeThickness = 1;
|
||
rectangle.Stroke = new SolidColorBrush(Color.FromRgb(0, 120, 215));
|
||
|
||
rectangle.Fill = new SolidColorBrush(Color.FromArgb(80, 0, 120, 215));
|
||
rectangle.Tag = "Rectangle";
|
||
|
||
map.Children.Add(rectangle);
|
||
startPosition = e.GetPosition(this);
|
||
MapLayer.SetPosition(rectangle, map.ViewportPointToLocation(startPosition));
|
||
drawRectangle = true;
|
||
};
|
||
|
||
map.MouseMove += (sender, e) =>
|
||
{
|
||
if (drawRectangle)
|
||
{
|
||
Point mousePosition = e.GetPosition(this);
|
||
rectangle.Width = Math.Abs(mousePosition.X - startPosition.X);
|
||
rectangle.Height = Math.Abs(mousePosition.Y - startPosition.Y);
|
||
leftTopPoint = new Point(Math.Min(mousePosition.X, startPosition.X), Math.Min(mousePosition.Y, startPosition.Y));
|
||
MapLayer.SetPosition(rectangle, map.ViewportPointToLocation(leftTopPoint));
|
||
}
|
||
};
|
||
int selectedCount = 0;
|
||
map.MouseRightButtonUp += (sender, e) =>
|
||
{
|
||
selectedCount = 0;
|
||
if (rectangle != null && map.Children.Contains(rectangle))
|
||
{
|
||
map.Children.Remove(rectangle);
|
||
if (_flightTaskManager.SelectedTask != null)
|
||
{
|
||
_copterManager.shiftkeydown = true;
|
||
_copterManager.Select(null);
|
||
foreach (FlightTaskSingleCopterInfo taskCopterInfo in _flightTaskManager.SelectedTask.SingleCopterInfos)
|
||
{
|
||
Location seekLocation = new Location(taskCopterInfo.TargetLat, taskCopterInfo.TargetLng);
|
||
Point seekPoint = map.LocationToViewportPoint(seekLocation);
|
||
if ((seekPoint.X > leftTopPoint.X && seekPoint.X < leftTopPoint.X + rectangle.Width) &&
|
||
seekPoint.Y > leftTopPoint.Y && seekPoint.Y < leftTopPoint.Y + rectangle.Height)
|
||
{
|
||
selectedCount++;
|
||
_copterManager.Select(taskCopterInfo.Copter);
|
||
}
|
||
}
|
||
_copterManager.shiftkeydown = false;
|
||
}
|
||
}
|
||
rectangle = null;
|
||
drawRectangle = false;
|
||
};
|
||
|
||
map.MouseLeave += (sender, e) =>
|
||
{
|
||
if (map.Children.Contains(rectangle))
|
||
{
|
||
map.Children.Remove(rectangle);
|
||
}
|
||
rectangle = null;
|
||
drawRectangle = false;
|
||
};
|
||
|
||
|
||
map.MouseMove += new MouseEventHandler(OriginalMove);
|
||
map.MouseLeftButtonUp += new MouseButtonEventHandler(OriginalMouseUp);
|
||
}
|
||
|
||
private CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
|
||
private MapManager _mapManager = ServiceLocator.Current.GetInstance<MapManager>();
|
||
private FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
|
||
private AppConfig _appConfig = ServiceLocator.Current.GetInstance<AppConfig>();
|
||
|
||
const string COPTER_TAG = "Copter";
|
||
const string WAYPOINT_TAG = "Waypoint";
|
||
const string ORIGINALPOINT_TAG = "Originalpoint";
|
||
|
||
public void Refresh()
|
||
{
|
||
foreach (var drawing in _copterDrawings.Values)
|
||
{
|
||
drawing.Track.Locations.Clear();
|
||
}
|
||
}
|
||
|
||
public bool RemoveLoadingErrorMessage()
|
||
{
|
||
var errorElement = map.Children.OfType<LoadingErrorMessage>().FirstOrDefault();
|
||
if (errorElement != null)
|
||
{
|
||
map.Children.Remove(errorElement);
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void GoHome()
|
||
{
|
||
map.ZoomLevel = 19;
|
||
map.Center = new Location(40.0559055, 116.322233);
|
||
}
|
||
|
||
|
||
|
||
private void Copters_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||
{
|
||
e.OldItems?.ForEach<ICopter>(async copter =>
|
||
{
|
||
copter.LocationChanged -= Copter_LocationChanged;
|
||
await Task.Delay(100); // 如果不等待一段时间,Copter_DataStreamReceived 很可能再被调用一次。
|
||
RemoveCopter(copter);
|
||
});
|
||
e.NewItems?.ForEach<ICopter>(copter => copter.LocationChanged += Copter_LocationChanged);
|
||
}
|
||
|
||
private void Copter_LocationChanged(object sender, EventArgs e)
|
||
{
|
||
var copter = sender as ICopter;
|
||
if (App.Current.CheckAccess())
|
||
{
|
||
AddOrMoveCopter(copter);
|
||
}
|
||
else
|
||
{
|
||
App.Current.Dispatcher.InvokeAsync(() => AddOrMoveCopter(copter));
|
||
}
|
||
}
|
||
|
||
private Dictionary<ICopter, CopterDrawing> _copterDrawings = new Dictionary<ICopter, CopterDrawing>();
|
||
private void AddOrMoveCopter(ICopter copter)
|
||
{
|
||
var drawing = _copterDrawings.ContainsKey(copter) ?
|
||
_copterDrawings[copter] :
|
||
(_copterDrawings[copter] = new CopterDrawing(copter, map));
|
||
drawing.AddOrMoveCopter();
|
||
}
|
||
|
||
private void RemoveCopter(ICopter copter)
|
||
{
|
||
if (_copterDrawings.ContainsKey(copter))
|
||
{
|
||
var drawing = _copterDrawings[copter];
|
||
drawing.RemoveCopter();
|
||
_copterDrawings.Remove(copter);
|
||
}
|
||
}
|
||
|
||
public void ClearCopters()
|
||
{
|
||
for (int i = map.Children.Count - 1; i >= 0; i--)
|
||
{
|
||
if (!(map.Children[i] is MapTileLayer))
|
||
{
|
||
map.Children.RemoveAt(i);
|
||
}
|
||
}
|
||
_copterDrawings.Clear();
|
||
}
|
||
|
||
private bool IsMouseOnCopterOrWaypoint(object originalSource)
|
||
{
|
||
var elem = originalSource as FrameworkElement;
|
||
string tag;
|
||
while (elem != map && elem != null)
|
||
{
|
||
tag = elem.Tag?.ToString();
|
||
if (tag == COPTER_TAG || tag == WAYPOINT_TAG || tag == ORIGINALPOINT_TAG)
|
||
{
|
||
return true;
|
||
}
|
||
elem = elem.Parent as FrameworkElement;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private void FlightTaskManager_TaskAdded(object sender, FlightTaskAddedEventArgs e)
|
||
{
|
||
foreach (var info in e.AddedTask.SingleCopterInfos)
|
||
{
|
||
var drawingInfo = _copterDrawings[info.Copter];
|
||
var location = new Location(info.TargetLat, info.TargetLng, info.TargetAlt);
|
||
drawingInfo.AddWaypoint(location, e.AddedTask.TaskType);
|
||
}
|
||
}
|
||
|
||
Ellipse original = null;
|
||
|
||
private void FlightTaskManager_SetOriginal(object sender, FlightTaskAddedOriginalEventArgs e)
|
||
{
|
||
if (map.Children.Contains(original))
|
||
return;
|
||
Location location = new Location();
|
||
if (e.Lat == 0 && e.Lng == 0)
|
||
location = map.Center;
|
||
else
|
||
location = new Location(e.Lat, e.Lng);
|
||
|
||
|
||
original = new Ellipse
|
||
{
|
||
Tag = ORIGINALPOINT_TAG,
|
||
Fill = new SolidColorBrush(Color.FromRgb(0, 0, 0)),
|
||
StrokeThickness = 3,
|
||
Stroke = new SolidColorBrush(Color.FromRgb(255, 255, 255)),
|
||
Width = 18,
|
||
Height = 18,
|
||
};
|
||
|
||
map.Children.Add(original);
|
||
MapLayer.SetPosition(original, location);
|
||
original.ToolTip = location.ToString();
|
||
originaDrag = false;
|
||
_flightTaskManager.OriginLat = location.Latitude;
|
||
_flightTaskManager.OriginLng = location.Longitude;
|
||
original.MouseLeftButtonDown += new MouseButtonEventHandler(OriginalMouseDown);
|
||
|
||
}
|
||
|
||
private bool originaDrag = false;
|
||
double wpOffsetX = 0;
|
||
double wpOffsetY = 0;
|
||
private void OriginalMouseDown(object sender, MouseButtonEventArgs e)
|
||
{
|
||
originaDrag = true;
|
||
var posInObject = e.GetPosition(original);
|
||
wpOffsetX = posInObject.X;
|
||
wpOffsetY = posInObject.Y;
|
||
}
|
||
|
||
private void OriginalMove(object sender, MouseEventArgs e)
|
||
{
|
||
if (originaDrag)
|
||
{
|
||
Point eventPos = e.GetPosition(map);
|
||
var leftTopPos = new Point(eventPos.X - wpOffsetX, eventPos.Y - wpOffsetY);
|
||
MapLayer.SetPosition(original, map.ViewportPointToLocation(leftTopPos));
|
||
}
|
||
|
||
}
|
||
|
||
private void OriginalMouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (originaDrag)
|
||
{
|
||
Point eventPos = e.GetPosition(map);
|
||
Location location = map.ViewportPointToLocation(eventPos);
|
||
_flightTaskManager.OriginLat = location.Latitude;
|
||
_flightTaskManager.OriginLng = location.Longitude;
|
||
original.ToolTip = location.ToString();
|
||
Console.WriteLine("original-----------"+original.ToolTip);
|
||
Clipboard.SetDataObject(string.Format("{0},{1}", location.Latitude, location.Longitude), true);
|
||
originaDrag = false;
|
||
}
|
||
}
|
||
|
||
|
||
private void MapSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||
{
|
||
switch ((e.AddedItems[0] as FrameworkElement).Tag.ToString())
|
||
{
|
||
case "卫星地图":
|
||
map.Mode = new AerialMode();
|
||
RemoveTileLayers();
|
||
break;
|
||
case "道路":
|
||
// map.Mode = new GoogleMode();
|
||
map.Mode = new RoadMode();
|
||
RemoveTileLayers();
|
||
break;
|
||
case "OpenStreet":
|
||
map.Mode = new MercatorMode();
|
||
if (!map.Children.OfType<OpenStreetMapTileLayer>().Any())
|
||
{
|
||
map.Children.Add(new OpenStreetMapTileLayer
|
||
{ UriFormat =
|
||
"http://tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||
});
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void showallpoint_Checked(object sender, RoutedEventArgs e)
|
||
{
|
||
CheckBox chk = (CheckBox)sender;
|
||
bool ischecked= chk.IsChecked ?? false;
|
||
|
||
foreach (var taskitme in _flightTaskManager.Tasks)
|
||
{
|
||
// if taskitme.IsRightSelected = chk.IsChecked ?? true;
|
||
|
||
if ((taskitme.IsRightSelected == ischecked) && (!taskitme.IsSelected))
|
||
{
|
||
_flightTaskManager.RightSelect(taskitme);
|
||
// TaskbarControl.setRightSelect(taskitme, ischecked);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
private void showpanline_Checked(object sender, RoutedEventArgs e)
|
||
{
|
||
CheckBox chk = (CheckBox)sender;
|
||
foreach (var item in _copterDrawings)
|
||
{
|
||
var copterDrawing = item.Value;
|
||
copterDrawing.SetShowroute(chk.IsChecked);
|
||
}
|
||
|
||
}
|
||
private void showrealtimeline_Checked(object sender, RoutedEventArgs e)
|
||
{
|
||
CheckBox chk = (CheckBox)sender;
|
||
foreach (var item in _copterDrawings)
|
||
{
|
||
var copterDrawing = item.Value;
|
||
copterDrawing.SetShowtrack (chk.IsChecked);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
private void RemoveTileLayers()
|
||
{
|
||
for (int i = map.Children.Count - 1; i >= 0; i--)
|
||
{
|
||
if (map.Children[i] is MapTileLayer)
|
||
{
|
||
map.Children.RemoveAt(i);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static class LocationExtensions
|
||
{
|
||
public static double CalcDistance(this Location loc1, Location loc2)
|
||
{
|
||
if (loc1 == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(loc1));
|
||
}
|
||
if (loc2 == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(loc2));
|
||
}
|
||
return GeographyUtils.CalcDistance(loc1.Latitude, loc1.Longitude, loc1.Altitude, loc2.Latitude, loc2.Longitude, loc2.Altitude);
|
||
}
|
||
}
|
||
}
|