Mini Kabibi Habibi
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Xml.Linq;
using System.Globalization;
using System.Collections;
using System.ComponentModel;
using System.Drawing.Imaging;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
namespace DevExpress.XtraMap.Demos {
public partial class MapElements : MapTutorialControl {
FlightMapDataGenerator dataGenerator;
VectorItemsLayer PlanesLayer { get { return (VectorItemsLayer)(mapControl1.Layers[2]); } }
VectorItemsLayer PathsLayer { get { return (VectorItemsLayer)(mapControl1.Layers[1]); } }
ImageTilesLayer TilesLayer { get { return (ImageTilesLayer)(mapControl1.Layers[0]); } }
PlaneInfoVisualizer planeInfoVisualizer;
public MapElements() {
InitializeComponent();
InitializePlaneInfoVisualizer();
mapControl1.SetMapItemFactory(new FlightMapFactory());
TilesLayer.DataProvider = CreateBingDataProvider(BingMapKind.Road);
dataGenerator = new FlightMapDataGenerator(planeInfoVisualizer);
dataGenerator.DataChanged += OnDataChanged;
PlanesLayer.DataSource = dataGenerator.Planes;
PathsLayer.DataSource = dataGenerator.AirPath;
UpdateSpeedScale();
}
void OnDataChanged(object sender, EventArgs e) {
foreach (PlaneInfo info in dataGenerator.Planes) {
if (!info.IsLanded) {
MapCustomElement item = PlanesLayer.GetMapItemBySourceObject(info) as MapCustomElement;
if (item != null) item.Location = new GeoPoint(info.Latitude, info.Longitude);
}
}
}
void InitializePlaneInfoVisualizer() {
planeInfoVisualizer = new PlaneInfoVisualizer() {
AltitudeLabel = lbAltitude,
SpeedLabel = lbSpeed,
FlightTimeLabel = lbFlightTime,
CurrentTimeLabel = lbCurrentTime,
ToLabel = lbTo,
FromLabel = lbFrom,
FlightNumberLabel = lbFlightNaumber,
NameLabel = lbName,
PlaneImage = pictureEdit1,
PlaneInfoPanel = planeInfoPanel
};
}
void mapControl1_DrawMapItem(object sender, DrawMapItemEventArgs e) {
DrawMapPointerEventArgs args = e as DrawMapPointerEventArgs;
if (args != null) {
MapItem item = e.Item;
InfoBase info = ((VectorItemsLayer)e.Item.Layer).GetItemSourceObject(item) as InfoBase;
if (info != null)
args.Image = info.Icon;
}
}
void mapControl1_SelectionChanged(object sender, MapSelectionChangedEventArgs e) {
if (e.Selection.Count > 0) {
dataGenerator.SelectedPlane = (PlaneInfo)PlanesLayer.GetItemSourceObject((MapItem)(e.Selection[0]));
return;
}
dataGenerator.SelectedPlane = null;
}
void trackBarControl1_ValueChanged(object sender, EventArgs e) {
UpdateSpeedScale();
}
void UpdateSpeedScale() {
if (dataGenerator != null) dataGenerator.SpeedScale = trackBarControl1.Value;
}
protected override void OnVisibleChanged(EventArgs e) {
base.OnVisibleChanged(e);
if (this.Visible)
dataGenerator.Start();
else
dataGenerator.Stop();
}
}
public abstract class InfoBase {
protected abstract MapItemType Type { get; }
public int ItemType { get { return (int)Type; } }
public virtual Image Icon { get { return null; } }
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class AirportInfo : InfoBase {
static Bitmap icon = new Bitmap(DemoUtils.GetRelativePath("\\Images\\Airport.png"));
protected override MapItemType Type { get { return MapItemType.Custom; } }
public override Image Icon { get { return icon; } }
public AirportInfo(GeoPoint location) {
this.Latitude = location.Latitude;
this.Longitude = location.Longitude;
}
}
public class PlaneTrajectory : InfoBase {
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;
MapSize sizeInKm = projection.GeoToKilometersSize(startPoint, new MapSize(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>();
readonly AirportInfo startPoint;
readonly AirportInfo endPoint;
protected override MapItemType Type { get { return MapItemType.Polyline; } }
public AirportInfo StartPoint { get { return startPoint; } }
public AirportInfo EndPoint { get { return endPoint; } }
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));
startPoint = new AirportInfo((trajectory.Count > 0) ? trajectory[0].StartPoint : new GeoPoint(0, 0));
endPoint = new AirportInfo((trajectory.Count > 0) ? trajectory[trajectory.Count - 1].EndPoint : new GeoPoint(0, 0));
}
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 : InfoBase {
static double Degree2Radian(double angleDegree) {
return angleDegree * Math.PI / 180.0;
}
static Image RotateImage(Image inputImage, double angleDegrees) {
Color backgroundColor = Color.Transparent;
bool upsizeOk = false;
bool clipOk = true;
if (angleDegrees == 0f)
return (Bitmap)inputImage.Clone();
int oldWidth = inputImage.Width;
int oldHeight = inputImage.Height;
int newWidth = oldWidth;
int newHeight = oldHeight;
float scaleFactor = 1f;
if (upsizeOk || !clipOk) {
double angleRadians = angleDegrees * Math.PI / 180d;
double cos = Math.Abs(Math.Cos(angleRadians));
double sin = Math.Abs(Math.Sin(angleRadians));
newWidth = (int)Math.Round(oldWidth * cos + oldHeight * sin);
newHeight = (int)Math.Round(oldWidth * sin + oldHeight * cos);
}
if (!upsizeOk && !clipOk) {
scaleFactor = Math.Min((float)oldWidth / newWidth, (float)oldHeight / newHeight);
newWidth = oldWidth;
newHeight = oldHeight;
}
Bitmap newBitmap = new Bitmap(newWidth, newHeight, backgroundColor == Color.Transparent ?
PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution);
using (Graphics graphicsObject = Graphics.FromImage(newBitmap)) {
graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphicsObject.SmoothingMode = SmoothingMode.HighQuality;
if (backgroundColor != Color.Transparent)
graphicsObject.Clear(backgroundColor);
graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f);
if (scaleFactor != 1f)
graphicsObject.ScaleTransform(scaleFactor, scaleFactor);
graphicsObject.RotateTransform((float)angleDegrees);
graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f);
graphicsObject.DrawImage(inputImage, 0, 0);
}
return newBitmap;
}
static string ConvertPlaneNameToFilePath(string PlaneName) {
string result = PlaneName.Replace(" ", "");
result = "\\Images\\Planes\\" + result.Replace("-", "") + ".png";
return DemoUtils.GetRelativePath(result);
}
bool isLandedField = false;
double currentFlightTime;
double course;
Image icon;
readonly Image sourceIcon;
readonly string planeIDField;
readonly string nameField;
readonly string endPointNameField;
readonly string startPointNameField;
readonly double speedInKmHField;
readonly double flightAltitudeField;
readonly Image imageField;
readonly PlaneTrajectory trajectoryField;
double Course {
get { return course; }
set {
if (course == value)
return;
course = value;
UpdateIcon();
}
}
protected override MapItemType Type { get { return MapItemType.Custom; } }
public double CurrentFlightTime {
get { return currentFlightTime; }
set {
if (currentFlightTime == value)
return;
currentFlightTime = value;
UpdatePosition(currentFlightTime);
}
}
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 Image Image { get { return imageField; } }
public bool IsLanded { get { return isLandedField; } }
public double TotalFlightTime { get { return trajectoryField.FlightTime; } }
public override Image Icon { get { return icon; } }
public PlaneInfo(string name, string id, string endPointName, string startPointName, double speedInKmH, double flightAltitude, List<GeoPoint> points, Image sourceIcon) {
this.nameField = name;
this.planeIDField = id;
this.sourceIcon = sourceIcon;
this.endPointNameField = endPointName;
this.startPointNameField = startPointName;
this.speedInKmHField = speedInKmH;
this.flightAltitudeField = flightAltitude;
this.imageField = new Bitmap(ConvertPlaneNameToFilePath(name));
trajectoryField = new PlaneTrajectory(points, speedInKmH);
UpdatePosition(CurrentFlightTime);
}
void UpdatePosition(double flightTime) {
isLandedField = flightTime >= trajectoryField.FlightTime;
GeoPoint point = trajectoryField.GetPointByCurrentFlightTime(flightTime);
Latitude = point.Latitude;
Longitude = point.Longitude;
Course = trajectoryField.GetCourseByCurrentFlightTime(flightTime);
}
void UpdateIcon() {
if (icon != null)
icon.Dispose();
icon = RotateImage(sourceIcon, Course);
}
public void UpdateAirPath(InfoList airPath) {
airPath.Add(trajectoryField);
airPath.Add(trajectoryField.StartPoint);
airPath.Add(trajectoryField.EndPoint);
}
}
public class FlightMapDataGenerator : IDisposable {
const double mSecPerHour = 3600000;
PlaneInfo selectedPlane;
DateTime lastTime;
bool isDisposed;
readonly InfoList planes = new InfoList();
readonly InfoList airPath = new InfoList();
readonly Timer timer = new Timer();
readonly Image sourcePlaneIcon;
readonly PlaneInfoVisualizer visualizer;
public InfoList Planes { get { return planes; } }
public InfoList AirPath { get { return airPath; } }
public PlaneInfo SelectedPlane {
get { return selectedPlane; }
set {
if (selectedPlane == value)
return;
selectedPlane = value;
UpdatePlaneInfo(selectedPlane);
}
}
public double SpeedScale { get; set; }
public FlightMapDataGenerator(PlaneInfoVisualizer visualizer) {
this.visualizer = visualizer;
sourcePlaneIcon = new Bitmap(DemoUtils.GetRelativePath("Images\\Plane.png"));
LoadFromXML();
timer.Tick += new EventHandler(OnTimedEvent);
timer.Interval = 2000;
SelectedPlane = (PlaneInfo)Planes[1];
}
~FlightMapDataGenerator() {
Dispose(false);
}
public event EventHandler DataChanged;
void RaiseDataChanged() {
if (DataChanged != null) DataChanged(this, EventArgs.Empty);
}
void LoadFromXML() {
XDocument document = DemoUtils.LoadXml("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, sourcePlaneIcon);
info.CurrentFlightTime = Convert.ToDouble(element.Element("CurrentFlightTime").Value, CultureInfo.InvariantCulture);
planes.Add(info);
}
}
}
void UpdatePlaneInfo(PlaneInfo planeInfo) {
visualizer.SelectedPlane = planeInfo;
airPath.Clear();
if (planeInfo != null)
planeInfo.UpdateAirPath(airPath);
}
void OnTimedEvent(object source, EventArgs e) {
DateTime currentTime = DateTime.Now;
TimeSpan interval = currentTime.Subtract(lastTime);
foreach (PlaneInfo info in planes) {
if (!info.IsLanded)
info.CurrentFlightTime += SpeedScale * interval.TotalMilliseconds / mSecPerHour;
}
lastTime = currentTime;
visualizer.Update();
RaiseDataChanged();
}
void Dispose(bool disposing) {
if (disposing && !isDisposed) {
isDisposed = true;
Stop();
if (timer != null)
timer.Dispose();
if (sourcePlaneIcon != null)
sourcePlaneIcon.Dispose();
}
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
public void Start() {
lastTime = DateTime.Now;
timer.Start();
}
public void Stop() {
timer.Stop();
}
}
public class PlaneInfoVisualizer {
PlaneInfo selectedPlane;
public LabelControl NameLabel { get; set; }
public LabelControl FlightNumberLabel { get; set; }
public LabelControl FromLabel { get; set; }
public LabelControl ToLabel { get; set; }
public LabelControl CurrentTimeLabel { get; set; }
public LabelControl FlightTimeLabel { get; set; }
public LabelControl SpeedLabel { get; set; }
public LabelControl AltitudeLabel { get; set; }
public PanelControl PlaneInfoPanel { get; set; }
public PictureEdit PlaneImage { get; set; }
public PlaneInfo SelectedPlane {
get { return selectedPlane; }
set {
if (selectedPlane == value)
return;
selectedPlane = value;
Update();
}
}
public void Update() {
if (selectedPlane == null) {
PlaneInfoPanel.Visible = false;
return;
}
PlaneInfoPanel.Visible = true;
NameLabel.Text = selectedPlane.Name;
FlightNumberLabel.Text = selectedPlane.PlaneID;
FromLabel.Text = selectedPlane.StartPointName;
ToLabel.Text = selectedPlane.EndPointName;
CurrentTimeLabel.Text = new TimeSpan(0, 0, (int)Math.Ceiling(selectedPlane.CurrentFlightTime * 3600)).ToString();
FlightTimeLabel.Text = new TimeSpan(0, 0, (int)Math.Ceiling(selectedPlane.TotalFlightTime * 3600)).ToString();
SpeedLabel.Text = selectedPlane.SpeedKmH.ToString();
AltitudeLabel.Text = selectedPlane.FlightAltitude.ToString();
PlaneImage.Image = selectedPlane.Image;
}
}
public class FlightMapFactory : DefaultMapItemFactory {
protected override void InitializeItem(MapItem item, object obj) {
base.InitializeItem(item, obj);
MapPolyline polyLine = item as MapPolyline;
PlaneTrajectory trajectory = obj as PlaneTrajectory;
if (polyLine != null && trajectory != null) {
polyLine.Points = trajectory.GetAirPath();
polyLine.Fill = Color.Empty;
polyLine.Stroke = Color.FromArgb(127, 255, 0, 199);
polyLine.StrokeWidth = 4;
}
}
}
public class InfoList : CollectionBase, IBindingList {
ListChangedEventHandler listChangedHandler;
public InfoBase this[int idx] { get { return (InfoBase)base.List[idx]; } }
public bool AllowEdit { get { return true; } }
public bool AllowNew { get { return false; } }
public bool AllowRemove { get { return true; } }
public event ListChangedEventHandler ListChanged {
add { listChangedHandler += value; }
remove { listChangedHandler -= value; }
}
protected override void OnRemoveComplete(int index, object value) {
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
}
protected override void OnInsertComplete(int index, object value) {
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
}
internal void OnListChanged(ListChangedEventArgs args) {
if (listChangedHandler != null) {
listChangedHandler(this, args);
}
}
protected override void OnClearComplete() {
base.OnClearComplete();
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
public void Add(InfoBase appointment) {
base.List.Add(appointment);
}
public int IndexOf(InfoBase appointment) {
return List.IndexOf(appointment);
}
public object AddNew() { throw new NotSupportedException(); }
public void AddIndex(PropertyDescriptor pd) { throw new NotSupportedException(); }
public void ApplySort(PropertyDescriptor pd, ListSortDirection dir) { throw new NotSupportedException(); }
public int Find(PropertyDescriptor property, object key) { throw new NotSupportedException(); }
public bool IsSorted { get { return false; } }
public void RemoveIndex(PropertyDescriptor pd) { throw new NotSupportedException(); }
public void RemoveSort() { throw new NotSupportedException(); }
public ListSortDirection SortDirection { get { throw new NotSupportedException(); } }
public PropertyDescriptor SortProperty { get { throw new NotSupportedException(); } }
public bool SupportsChangeNotification { get { return true; } }
public bool SupportsSearching { get { return false; } }
public bool SupportsSorting { get { return false; } }
}
}