Mini Kabibi Habibi
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Threading;
using System.Xml.Linq;
using DevExpress.Xpf.Map;
namespace MapDemo {
public partial class MapElements : MapDemoModule {
FlightMapDataGenerator dataGenerator;
public MapElements() {
InitializeComponent();
dataGenerator = new FlightMapDataGenerator(Resources["airportTemplate"] as DataTemplate, Resources["planeTemplate"] as DataTemplate, planeInfoPanel);
DataContext = dataGenerator;
dataGenerator.SpeedScale = Convert.ToDouble(tbSpeedScale.Value);
}
void tbSpeedScale_EditValueChanged(object sender, DevExpress.Xpf.Editors.EditValueChangedEventArgs e) {
if (dataGenerator != null)
dataGenerator.SpeedScale = Convert.ToDouble(e.NewValue);
}
}
public class PlaneTrajectory {
class TrajectoryPart {
readonly GeoPoint startPointField;
readonly GeoPoint endPointField;
readonly double flightTimeField;
readonly double courseField;
public GeoPoint StartPoint { get { return startPointField; } }
public GeoPoint EndPoint { get { return endPointField; } }
public double FlightTime { get { return flightTimeField; } }
public double Course { get { return courseField; } }
public TrajectoryPart(IProjection projection, GeoPoint startPoint, GeoPoint endPoint, double speedInKmH) {
this.startPointField = startPoint;
this.endPointField = endPoint;
Size sizeInKm = projection.GeoToKilometersSize(startPoint, new Size(Math.Abs(startPoint.Longitude - endPoint.Longitude), Math.Abs(startPoint.Latitude - endPoint.Latitude)));
double partlength = Math.Sqrt(sizeInKm.Width * sizeInKm.Width + sizeInKm.Height * sizeInKm.Height);
flightTimeField = partlength / speedInKmH;
courseField = Math.Atan2((endPoint.Longitude - startPoint.Longitude), (endPoint.Latitude - startPoint.Latitude)) * 180 / Math.PI;
}
public GeoPoint GetPointByCurrentFlightTime(double currentFlightTime, IProjection projection) {
if (currentFlightTime > FlightTime)
return endPointField;
double ratio = currentFlightTime / FlightTime;
return new GeoPoint(startPointField.Latitude + ratio * (endPointField.Latitude - startPointField.Latitude), startPointField.Longitude + ratio * (endPointField.Longitude - startPointField.Longitude));
}
}
readonly List<TrajectoryPart> trajectory = new List<TrajectoryPart>();
public GeoPoint StartPoint {
get { return (trajectory.Count > 0) ? trajectory[0].StartPoint : new GeoPoint(0, 0); }
}
public GeoPoint EndPoint {
get { return (trajectory.Count > 0) ? trajectory[trajectory.Count - 1].EndPoint : new GeoPoint(0, 0); }
}
public double FlightTime {
get {
double result = 0.0;
foreach (TrajectoryPart part in trajectory)
result += part.FlightTime;
return result;
}
}
public PlaneTrajectory(List<GeoPoint> points, double speedInKmH) {
SphericalMercatorProjection projection = new SphericalMercatorProjection();
for (int i = 0; i < points.Count - 1; i++)
trajectory.Add(new TrajectoryPart(projection, points[i], points[i + 1], speedInKmH));
}
public GeoPoint GetPointByCurrentFlightTime(double currentFlightTime) {
SphericalMercatorProjection projection = new SphericalMercatorProjection();
double time = 0.0;
for (int i = 0; i < trajectory.Count - 1; i++) {
if (trajectory[i].FlightTime > currentFlightTime - time)
return trajectory[i].GetPointByCurrentFlightTime(currentFlightTime - time, projection);
time += trajectory[i].FlightTime;
}
return trajectory[trajectory.Count - 1].GetPointByCurrentFlightTime(currentFlightTime - time, projection);
}
public GeoPointCollection GetAirPath() {
GeoPointCollection result = new GeoPointCollection();
double currentFlightTime = 0.0;
while (currentFlightTime < FlightTime) {
result.Add(GetPointByCurrentFlightTime(currentFlightTime));
currentFlightTime += 0.001;
}
result.Add(GetPointByCurrentFlightTime(FlightTime));
return result;
}
public double GetCourseByCurrentFlightTime(double currentFlightTime) {
double time = 0.0;
for (int i = 0; i < trajectory.Count - 1; i++) {
if (trajectory[i].FlightTime > currentFlightTime - time)
return trajectory[i].Course;
time += trajectory[i].FlightTime;
}
return trajectory[trajectory.Count - 1].Course;
}
}
public class PlaneInfo : DependencyObject {
public static readonly DependencyProperty CurrentFlightTimeProperty = DependencyProperty.Register("CurrentFlightTime",
typeof(double), typeof(PlaneInfo), new PropertyMetadata(0.0, new PropertyChangedCallback(CurrentFlightTimePropertyChanged)));
public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position",
typeof(GeoPoint), typeof(PlaneInfo), new PropertyMetadata(new GeoPoint(0, 0)));
public static readonly DependencyProperty CourseProperty = DependencyProperty.Register("Course",
typeof(double), typeof(PlaneInfo), new PropertyMetadata(0.0));
public double CurrentFlightTime {
get { return (double)GetValue(CurrentFlightTimeProperty); }
set { SetValue(CurrentFlightTimeProperty, value); }
}
public GeoPoint Position {
get { return (GeoPoint)GetValue(PositionProperty); }
}
public double Course {
get { return (double)GetValue(CourseProperty); }
}
static void CurrentFlightTimePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
PlaneInfo info = d as PlaneInfo;
if (info != null)
info.UpdatePosition((double)e.NewValue);
}
static string ConvertPlaneNameToFilePath(string PlaneName) {
string result = PlaneName.Replace(" ", "");
result = "../Images/Planes/" + result.Replace("-", "") + ".png";
return result;
}
bool isLandedField = false;
readonly string planeIDField;
readonly string nameField;
readonly string endPointNameField;
readonly string startPointNameField;
readonly double speedInKmHField;
readonly double flightAltitudeField;
readonly string imagePathField;
readonly PlaneTrajectory trajectoryField;
public string PlaneID { get { return planeIDField; } }
public string Name { get { return nameField; } }
public string EndPointName { get { return endPointNameField; } }
public string StartPointName { get { return startPointNameField; } }
public double SpeedKmH { get { return isLandedField ? 0.0 : speedInKmHField; } }
public double FlightAltitude { get { return isLandedField ? 0.0 : flightAltitudeField; } }
public string ImagePath { get { return imagePathField; } }
public bool IsLanded { get { return isLandedField; } }
public double TotalFlightTime { get { return trajectoryField.FlightTime; } }
public PlaneInfo(string name, string id, string endPointName, string startPointName, double speedInKmH, double flightAltitude, List<GeoPoint> points) {
this.nameField = name;
this.planeIDField = id;
this.endPointNameField = endPointName;
this.startPointNameField = startPointName;
this.speedInKmHField = speedInKmH;
this.flightAltitudeField = flightAltitude;
imagePathField = ConvertPlaneNameToFilePath(name);
trajectoryField = new PlaneTrajectory(points, speedInKmH);
UpdatePosition(CurrentFlightTime);
}
void UpdatePosition(double flightTime) {
GeoPoint pos = trajectoryField.GetPointByCurrentFlightTime(flightTime);
double course = trajectoryField.GetCourseByCurrentFlightTime(flightTime);
isLandedField = flightTime >= trajectoryField.FlightTime;
SetValue(PositionProperty, pos);
SetValue(CourseProperty, course);
}
public List<MapItem> GetAirPath(DataTemplate airportTemplate) {
List<MapItem> mapItemList = new List<MapItem>();
mapItemList.Add(new MapPolyline() { Points = trajectoryField.GetAirPath(), Fill = new SolidColorBrush(Colors.Transparent), Stroke = new SolidColorBrush(Color.FromArgb(127, 255, 0, 199)), StrokeStyle = new StrokeStyle() { Thickness = 4 } });
mapItemList.Add(new MapCustomElement() { Location = trajectoryField.StartPoint, ContentTemplate = airportTemplate });
mapItemList.Add(new MapCustomElement() { Location = trajectoryField.EndPoint, ContentTemplate = airportTemplate });
return mapItemList;
}
}
public class FlightMapDataGenerator : DependencyObject {
public static readonly DependencyProperty PlanesProperty = DependencyProperty.Register("Planes",
typeof(ObservableCollection<MapCustomElement>), typeof(FlightMapDataGenerator), new PropertyMetadata(null));
public static readonly DependencyProperty ActualAirPathProperty = DependencyProperty.Register("ActualAirPath",
typeof(ObservableCollection<MapItem>), typeof(FlightMapDataGenerator), new PropertyMetadata(null));
public static readonly DependencyProperty ActualPlaneInfoProperty = DependencyProperty.Register("ActualPlaneInfo",
typeof(PlaneInfo), typeof(FlightMapDataGenerator), new PropertyMetadata(null));
public static readonly DependencyProperty SelectedPlaneProperty = DependencyProperty.Register("SelectedPlane",
typeof(MapCustomElement), typeof(FlightMapDataGenerator), new PropertyMetadata(null, new PropertyChangedCallback(SelectedPlaneProperyChanged)));
public ObservableCollection<MapCustomElement> Planes {
get { return (ObservableCollection<MapCustomElement>)GetValue(PlanesProperty); }
}
public ObservableCollection<MapItem> ActualAirPath {
get { return (ObservableCollection<MapItem>)GetValue(ActualAirPathProperty); }
}
public PlaneInfo ActualPlaneInfo {
get { return (PlaneInfo)GetValue(ActualPlaneInfoProperty); }
set { SetValue(ActualPlaneInfoProperty, value); }
}
public MapCustomElement SelectedPlane {
get { return (MapCustomElement)GetValue(SelectedPlaneProperty); }
set { SetValue(SelectedPlaneProperty, value); }
}
public double SpeedScale {
get { return speedScaleField; }
set { speedScaleField = value; }
}
static void SelectedPlaneProperyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
FlightMapDataGenerator flightMapDataGenerator = d as FlightMapDataGenerator;
if (flightMapDataGenerator != null)
flightMapDataGenerator.UpdatePlaneInfo(e.NewValue as MapCustomElement);
}
const double mSecPerHour = 3600000;
readonly DispatcherTimer timer = new DispatcherTimer();
readonly DataTemplate airportTemplate;
readonly List<PlaneInfo> planesInfo = new List<PlaneInfo>();
readonly PlaneInfoPanel infoPanel;
double speedScaleField;
DateTime lastTime;
public FlightMapDataGenerator(DataTemplate airportTemplate, DataTemplate planeTemplate, PlaneInfoPanel infoPanel) {
this.SetValue(PlanesProperty, new ObservableCollection<MapCustomElement>());
this.SetValue(ActualAirPathProperty, new ObservableCollection<MapItem>());
this.airportTemplate = airportTemplate;
this.infoPanel = infoPanel;
LoadFromXML(planeTemplate);
timer.Tick += new EventHandler(OnTimedEvent);
timer.Interval = new TimeSpan(0, 0, 2);
lastTime = DateTime.Now;
timer.Start();
if (Planes != null)
SelectedPlane = Planes[1];
}
void LoadFromXML(DataTemplate planeTemplate) {
XDocument document = DataLoader.LoadXmlFromResources("/Data/FlightMap.xml");
if (document != null) {
foreach (XElement element in document.Element("Planes").Elements()) {
List<GeoPoint> points = new List<GeoPoint>();
foreach (XElement infoElement in element.Element("Path").Elements()) {
GeoPoint geoPoint = new GeoPoint(Convert.ToDouble(infoElement.Element("Latitude").Value, CultureInfo.InvariantCulture), Convert.ToDouble(infoElement.Element("Longitude").Value, CultureInfo.InvariantCulture));
points.Add(geoPoint);
}
PlaneInfo info = new PlaneInfo(element.Element("PlaneName").Value, element.Element("PlaneID").Value, element.Element("EndPointName").Value, element.Element("StartPointName").Value, Convert.ToInt32(element.Element("Speed").Value), Convert.ToInt32(element.Element("Altitude").Value), points);
info.CurrentFlightTime = Convert.ToDouble(element.Element("CurrentFlightTime").Value, CultureInfo.InvariantCulture);
planesInfo.Add(info);
}
}
foreach (PlaneInfo info in planesInfo) {
MapCustomElement mapCustomElement = new MapCustomElement() { Content = info, ContentTemplate = planeTemplate };
BindingOperations.SetBinding(mapCustomElement, MapCustomElement.LocationProperty, new Binding("Position") { Source = info });
Planes.Add(mapCustomElement);
}
}
void UpdateCurrentPath(PlaneInfo planeInfo) {
ActualAirPath.Clear();
if (planeInfo != null)
foreach (MapItem item in planeInfo.GetAirPath(airportTemplate))
ActualAirPath.Add(item);
}
void UpdatePlaneInfo(MapCustomElement plane) {
ActualPlaneInfo = (plane != null) ? (plane.Content as PlaneInfo) : null;
infoPanel.Visible = ActualPlaneInfo != null;
UpdateCurrentPath(ActualPlaneInfo);
}
void OnTimedEvent(object source, EventArgs e) {
DateTime currentTime = DateTime.Now;
TimeSpan interval = currentTime.Subtract(lastTime);
foreach (PlaneInfo info in planesInfo) {
if (!info.IsLanded)
info.CurrentFlightTime += speedScaleField * interval.TotalMilliseconds / mSecPerHour;
}
lastTime = currentTime;
}
}
}