Mini Kabibi Habibi

Current Path : C:/Users/Public/Documents/DXperience 13.1 Demos/WinForms/VB/MapMainDemo/Modules/
Upload File :
Current File : C:/Users/Public/Documents/DXperience 13.1 Demos/WinForms/VB/MapMainDemo/Modules/MapElements.vb

Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Collections.Generic
Imports System.Drawing.Drawing2D
Imports System.Xml.Linq
Imports System.Globalization
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing.Imaging
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Controls

Namespace DevExpress.XtraMap.Demos

	Partial Public Class MapElements
		Inherits MapTutorialControl
		Private dataGenerator As FlightMapDataGenerator
		Private ReadOnly Property PlanesLayer() As VectorItemsLayer
			Get
				Return CType(mapControl1.Layers(2), VectorItemsLayer)
			End Get
		End Property
		Private ReadOnly Property PathsLayer() As VectorItemsLayer
			Get
				Return CType(mapControl1.Layers(1), VectorItemsLayer)
			End Get
		End Property
		Private ReadOnly Property TilesLayer() As ImageTilesLayer
			Get
				Return CType(mapControl1.Layers(0), ImageTilesLayer)
			End Get
		End Property
		Private planeInfoVisualizer As PlaneInfoVisualizer


		Public Sub New()
			InitializeComponent()
			InitializePlaneInfoVisualizer()
			mapControl1.SetMapItemFactory(New FlightMapFactory())
			TilesLayer.DataProvider = CreateBingDataProvider(BingMapKind.Road)
			dataGenerator = New FlightMapDataGenerator(planeInfoVisualizer)
			AddHandler dataGenerator.DataChanged, AddressOf OnDataChanged
			PlanesLayer.DataSource = dataGenerator.Planes
			PathsLayer.DataSource = dataGenerator.AirPath
			UpdateSpeedScale()
		End Sub

		Private Sub OnDataChanged(ByVal sender As Object, ByVal e As EventArgs)
			For Each info As PlaneInfo In dataGenerator.Planes
				If (Not info.IsLanded) Then
					Dim item As MapCustomElement = TryCast(PlanesLayer.GetMapItemBySourceObject(info), MapCustomElement)
					If item IsNot Nothing Then
						item.Location = New GeoPoint(info.Latitude, info.Longitude)
					End If
				End If
			Next info
		End Sub

		Private Sub InitializePlaneInfoVisualizer()
			planeInfoVisualizer = New PlaneInfoVisualizer() With {.AltitudeLabel = lbAltitude, .SpeedLabel = lbSpeed, .FlightTimeLabel = lbFlightTime, .CurrentTimeLabel = lbCurrentTime, .ToLabel = lbTo, .FromLabel = lbFrom, .FlightNumberLabel = lbFlightNaumber, .NameLabel = lbName, .PlaneImage = pictureEdit1, .PlaneInfoPanel = planeInfoPanel}
		End Sub
		Private Sub mapControl1_DrawMapItem(ByVal sender As Object, ByVal e As DrawMapItemEventArgs) Handles mapControl1.DrawMapItem
			Dim args As DrawMapPointerEventArgs = TryCast(e, DrawMapPointerEventArgs)
			If args IsNot Nothing Then
				Dim item As MapItem = e.Item
				Dim info As InfoBase = TryCast((CType(e.Item.Layer, VectorItemsLayer)).GetItemSourceObject(item), InfoBase)
				If info IsNot Nothing Then
					args.Image = info.Icon
				End If
			End If
		End Sub
		Private Sub mapControl1_SelectionChanged(ByVal sender As Object, ByVal e As MapSelectionChangedEventArgs) Handles mapControl1.SelectionChanged
			If e.Selection.Count > 0 Then
				dataGenerator.SelectedPlane = CType(PlanesLayer.GetItemSourceObject(CType(e.Selection(0), MapItem)), PlaneInfo)
				Return
			End If
			dataGenerator.SelectedPlane = Nothing
		End Sub
		Private Sub trackBarControl1_ValueChanged(ByVal sender As Object, ByVal e As EventArgs) Handles trackBarControl1.ValueChanged
			UpdateSpeedScale()
		End Sub
		Private Sub UpdateSpeedScale()
			If dataGenerator IsNot Nothing Then
				dataGenerator.SpeedScale = trackBarControl1.Value
			End If
		End Sub
		Protected Overrides Sub OnVisibleChanged(ByVal e As EventArgs)
			MyBase.OnVisibleChanged(e)
			If Me.Visible Then
				dataGenerator.Start()
			Else
				dataGenerator.Stop()
			End If
		End Sub
	End Class

	Public MustInherit Class InfoBase
		Protected MustOverride ReadOnly Property Type() As MapItemType
		Public ReadOnly Property ItemType() As Integer
			Get
				Return CInt(Fix(Type))
			End Get
		End Property
		Public Overridable ReadOnly Property Icon() As Image
			Get
				Return Nothing
			End Get
		End Property

		Private privateLatitude As Double
		Public Property Latitude() As Double
			Get
				Return privateLatitude
			End Get
			Set(ByVal value As Double)
				privateLatitude = value
			End Set
		End Property
		Private privateLongitude As Double
		Public Property Longitude() As Double
			Get
				Return privateLongitude
			End Get
			Set(ByVal value As Double)
				privateLongitude = value
			End Set
		End Property
	End Class

	Public Class AirportInfo
		Inherits InfoBase
		Private Shared icon_Renamed As New Bitmap(DemoUtils.GetRelativePath("\Images\Airport.png"))

		Protected Overrides ReadOnly Property Type() As MapItemType
			Get
				Return MapItemType.Custom
			End Get
		End Property
		Public Overrides ReadOnly Property Icon() As Image
			Get
				Return icon_Renamed
			End Get
		End Property

		Public Sub New(ByVal location As GeoPoint)
			Me.Latitude = location.Latitude
			Me.Longitude = location.Longitude
		End Sub
	End Class

	Public Class PlaneTrajectory
		Inherits InfoBase
		Private Class TrajectoryPart
			Private ReadOnly startPointField As GeoPoint
			Private ReadOnly endPointField As GeoPoint
			Private ReadOnly flightTimeField As Double
			Private ReadOnly courseField As Double

			Public ReadOnly Property StartPoint() As GeoPoint
				Get
					Return startPointField
				End Get
			End Property
			Public ReadOnly Property EndPoint() As GeoPoint
				Get
					Return endPointField
				End Get
			End Property
			Public ReadOnly Property FlightTime() As Double
				Get
					Return flightTimeField
				End Get
			End Property
			Public ReadOnly Property Course() As Double
				Get
					Return courseField
				End Get
			End Property

			Public Sub New(ByVal projection As IProjection, ByVal startPoint As GeoPoint, ByVal endPoint As GeoPoint, ByVal speedInKmH As Double)
				Me.startPointField = startPoint
				Me.endPointField = endPoint
				Dim sizeInKm As MapSize = projection.GeoToKilometersSize(startPoint, New MapSize(Math.Abs(startPoint.Longitude - endPoint.Longitude), Math.Abs(startPoint.Latitude - endPoint.Latitude)))
				Dim partlength As Double = 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
			End Sub
			Public Function GetPointByCurrentFlightTime(ByVal currentFlightTime As Double, ByVal projection As IProjection) As GeoPoint
				If currentFlightTime > FlightTime Then
					Return endPointField
				End If
				Dim ratio As Double = currentFlightTime / FlightTime
				Return New GeoPoint(startPointField.Latitude + ratio * (endPointField.Latitude - startPointField.Latitude), startPointField.Longitude + ratio * (endPointField.Longitude - startPointField.Longitude))
			End Function
		End Class

		Private ReadOnly trajectory As New List(Of TrajectoryPart)()
		Private ReadOnly startPoint_Renamed As AirportInfo
		Private ReadOnly endPoint_Renamed As AirportInfo

		Protected Overrides ReadOnly Property Type() As MapItemType
			Get
				Return MapItemType.Polyline
			End Get
		End Property
		Public ReadOnly Property StartPoint() As AirportInfo
			Get
				Return startPoint_Renamed
			End Get
		End Property
		Public ReadOnly Property EndPoint() As AirportInfo
			Get
				Return endPoint_Renamed
			End Get
		End Property
		Public ReadOnly Property FlightTime() As Double
			Get
				Dim result As Double = 0.0
				For Each part As TrajectoryPart In trajectory
					result += part.FlightTime
				Next part
				Return result
			End Get
		End Property

		Public Sub New(ByVal points As List(Of GeoPoint), ByVal speedInKmH As Double)
			Dim projection As New SphericalMercatorProjection()
			For i As Integer = 0 To points.Count - 2
				trajectory.Add(New TrajectoryPart(projection, points(i), points(i + 1), speedInKmH))
			Next i
			startPoint_Renamed = New AirportInfo(If((trajectory.Count > 0), trajectory(0).StartPoint, New GeoPoint(0, 0)))
			endPoint_Renamed = New AirportInfo(If((trajectory.Count > 0), trajectory(trajectory.Count - 1).EndPoint, New GeoPoint(0, 0)))
		End Sub
		Public Function GetPointByCurrentFlightTime(ByVal currentFlightTime As Double) As GeoPoint
			Dim projection As New SphericalMercatorProjection()
			Dim time As Double = 0.0
			For i As Integer = 0 To trajectory.Count - 2
				If trajectory(i).FlightTime > currentFlightTime - time Then
					Return trajectory(i).GetPointByCurrentFlightTime(currentFlightTime - time, projection)
				End If
				time += trajectory(i).FlightTime
			Next i
			Return trajectory(trajectory.Count - 1).GetPointByCurrentFlightTime(currentFlightTime - time, projection)
		End Function
		Public Function GetAirPath() As GeoPointCollection
			Dim result As New GeoPointCollection()
			Dim currentFlightTime As Double = 0.0
			Do While currentFlightTime < FlightTime
				result.Add(GetPointByCurrentFlightTime(currentFlightTime))
				currentFlightTime += 0.001
			Loop
			result.Add(GetPointByCurrentFlightTime(FlightTime))
			Return result
		End Function
		Public Function GetCourseByCurrentFlightTime(ByVal currentFlightTime As Double) As Double
			Dim time As Double = 0.0
			For i As Integer = 0 To trajectory.Count - 2
				If trajectory(i).FlightTime > currentFlightTime - time Then
					Return trajectory(i).Course
				End If
				time += trajectory(i).FlightTime
			Next i
			Return trajectory(trajectory.Count - 1).Course
		End Function
	End Class

	Public Class PlaneInfo
		Inherits InfoBase
		Private Shared Function Degree2Radian(ByVal angleDegree As Double) As Double
			Return angleDegree * Math.PI / 180.0
		End Function

		Private Shared Function RotateImage(ByVal inputImage As Image, ByVal angleDegrees As Double) As Image
			Dim backgroundColor As Color = Color.Transparent
			Dim upsizeOk As Boolean = False
			Dim clipOk As Boolean = True
			If angleDegrees = 0f Then
				Return CType(inputImage.Clone(), Bitmap)
			End If

			Dim oldWidth As Integer = inputImage.Width
			Dim oldHeight As Integer = inputImage.Height
			Dim newWidth As Integer = oldWidth
			Dim newHeight As Integer = oldHeight
			Dim scaleFactor As Single = 1f

			If upsizeOk OrElse (Not clipOk) Then
				Dim angleRadians As Double = angleDegrees * Math.PI / 180R
				Dim cos As Double = Math.Abs(Math.Cos(angleRadians))
				Dim sin As Double = Math.Abs(Math.Sin(angleRadians))
				newWidth = CInt(Fix(Math.Round(oldWidth * cos + oldHeight * sin)))
				newHeight = CInt(Fix(Math.Round(oldWidth * sin + oldHeight * cos)))
			End If
			If (Not upsizeOk) AndAlso (Not clipOk) Then
				scaleFactor = Math.Min(CSng(oldWidth) / newWidth, CSng(oldHeight) / newHeight)
				newWidth = oldWidth
				newHeight = oldHeight
			End If
			Dim newBitmap As New Bitmap(newWidth, newHeight,If(backgroundColor = Color.Transparent, PixelFormat.Format32bppArgb, PixelFormat.Format24bppRgb))
			newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution)
			Using graphicsObject As Graphics = Graphics.FromImage(newBitmap)
				graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic
				graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality
				graphicsObject.SmoothingMode = SmoothingMode.HighQuality
				If backgroundColor <> Color.Transparent Then
					graphicsObject.Clear(backgroundColor)
				End If
				graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f)
				If scaleFactor <> 1f Then
					graphicsObject.ScaleTransform(scaleFactor, scaleFactor)
				End If
				graphicsObject.RotateTransform(CSng(angleDegrees))
				graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f)
				graphicsObject.DrawImage(inputImage, 0, 0)
			End Using
			Return newBitmap
		End Function
		Private Shared Function ConvertPlaneNameToFilePath(ByVal PlaneName As String) As String
			Dim result As String = PlaneName.Replace(" ", "")
			result = "\Images\Planes\" & result.Replace("-", "") & ".png"
			Return DemoUtils.GetRelativePath(result)
		End Function

		Private isLandedField As Boolean = False
		Private currentFlightTime_Renamed As Double
		Private course_Renamed As Double
		Private icon_Renamed As Image
		Private ReadOnly sourceIcon As Image
		Private ReadOnly planeIDField As String
		Private ReadOnly nameField As String
		Private ReadOnly endPointNameField As String
		Private ReadOnly startPointNameField As String
		Private ReadOnly speedInKmHField As Double
		Private ReadOnly flightAltitudeField As Double
		Private ReadOnly imageField As Image
		Private ReadOnly trajectoryField As PlaneTrajectory

		Private Property Course() As Double
			Get
				Return course_Renamed
			End Get
			Set(ByVal value As Double)
				If course_Renamed = value Then
					Return
				End If
				course_Renamed = value
				UpdateIcon()
			End Set
		End Property
		Protected Overrides ReadOnly Property Type() As MapItemType
			Get
				Return MapItemType.Custom
			End Get
		End Property
		Public Property CurrentFlightTime() As Double
			Get
				Return currentFlightTime_Renamed
			End Get
			Set(ByVal value As Double)
				If currentFlightTime_Renamed = value Then
					Return
				End If
				currentFlightTime_Renamed = value
				UpdatePosition(currentFlightTime_Renamed)
			End Set
		End Property
		Public ReadOnly Property PlaneID() As String
			Get
				Return planeIDField
			End Get
		End Property
		Public ReadOnly Property Name() As String
			Get
				Return nameField
			End Get
		End Property
		Public ReadOnly Property EndPointName() As String
			Get
				Return endPointNameField
			End Get
		End Property
		Public ReadOnly Property StartPointName() As String
			Get
				Return startPointNameField
			End Get
		End Property
		Public ReadOnly Property SpeedKmH() As Double
			Get
				Return If(isLandedField, 0.0, speedInKmHField)
			End Get
		End Property
		Public ReadOnly Property FlightAltitude() As Double
			Get
				Return If(isLandedField, 0.0, flightAltitudeField)
			End Get
		End Property
		Public ReadOnly Property Image() As Image
			Get
				Return imageField
			End Get
		End Property
		Public ReadOnly Property IsLanded() As Boolean
			Get
				Return isLandedField
			End Get
		End Property
		Public ReadOnly Property TotalFlightTime() As Double
			Get
				Return trajectoryField.FlightTime
			End Get
		End Property
		Public Overrides ReadOnly Property Icon() As Image
			Get
				Return icon_Renamed
			End Get
		End Property

		Public Sub New(ByVal name As String, ByVal id As String, ByVal endPointName As String, ByVal startPointName As String, ByVal speedInKmH As Double, ByVal flightAltitude As Double, ByVal points As List(Of GeoPoint), ByVal sourceIcon As Image)
			Me.nameField = name
			Me.planeIDField = id
			Me.sourceIcon = sourceIcon
			Me.endPointNameField = endPointName
			Me.startPointNameField = startPointName
			Me.speedInKmHField = speedInKmH
			Me.flightAltitudeField = flightAltitude
			Me.imageField = New Bitmap(ConvertPlaneNameToFilePath(name))
			trajectoryField = New PlaneTrajectory(points, speedInKmH)
			UpdatePosition(CurrentFlightTime)
		End Sub
		Private Sub UpdatePosition(ByVal flightTime As Double)
			isLandedField = flightTime >= trajectoryField.FlightTime
			Dim point As GeoPoint = trajectoryField.GetPointByCurrentFlightTime(flightTime)
			Latitude = point.Latitude
			Longitude = point.Longitude
			Course = trajectoryField.GetCourseByCurrentFlightTime(flightTime)
		End Sub
		Private Sub UpdateIcon()
			If icon_Renamed IsNot Nothing Then
				icon_Renamed.Dispose()
			End If
			icon_Renamed = RotateImage(sourceIcon, Course)
		End Sub
		Public Sub UpdateAirPath(ByVal airPath As InfoList)
			airPath.Add(trajectoryField)
			airPath.Add(trajectoryField.StartPoint)
			airPath.Add(trajectoryField.EndPoint)
		End Sub
	End Class

	Public Class FlightMapDataGenerator
		Implements IDisposable
		Private Const mSecPerHour As Double = 3600000

		Private selectedPlane_Renamed As PlaneInfo
		Private lastTime As DateTime
		Private isDisposed As Boolean
		Private ReadOnly planes_Renamed As New InfoList()
		Private ReadOnly airPath_Renamed As New InfoList()
		Private ReadOnly timer As New Timer()
		Private ReadOnly sourcePlaneIcon As Image
		Private ReadOnly visualizer As PlaneInfoVisualizer

		Public ReadOnly Property Planes() As InfoList
			Get
				Return planes_Renamed
			End Get
		End Property
		Public ReadOnly Property AirPath() As InfoList
			Get
				Return airPath_Renamed
			End Get
		End Property
		Public Property SelectedPlane() As PlaneInfo
			Get
				Return selectedPlane_Renamed
			End Get
			Set(ByVal value As PlaneInfo)
				If selectedPlane_Renamed Is value Then
					Return
				End If
				selectedPlane_Renamed = value
				UpdatePlaneInfo(selectedPlane_Renamed)
			End Set
		End Property
		Private privateSpeedScale As Double
		Public Property SpeedScale() As Double
			Get
				Return privateSpeedScale
			End Get
			Set(ByVal value As Double)
				privateSpeedScale = value
			End Set
		End Property

		Public Sub New(ByVal visualizer As PlaneInfoVisualizer)
			Me.visualizer = visualizer
			sourcePlaneIcon = New Bitmap(DemoUtils.GetRelativePath("Images\Plane.png"))
			LoadFromXML()
			AddHandler timer.Tick, AddressOf OnTimedEvent
			timer.Interval = 2000
			SelectedPlane = CType(Planes(1), PlaneInfo)
		End Sub
		Protected Overrides Sub Finalize()
			Dispose(False)
		End Sub

		Public Event DataChanged As EventHandler

		Private Sub RaiseDataChanged()
			RaiseEvent DataChanged(Me, EventArgs.Empty)
		End Sub
		Private Sub LoadFromXML()
			Dim document As XDocument = DemoUtils.LoadXml("FlightMap.xml")
			If document IsNot Nothing Then
				For Each element As XElement In document.Element("Planes").Elements()
					Dim points As New List(Of GeoPoint)()
					For Each infoElement As XElement In element.Element("Path").Elements()
						Dim geoPoint As New GeoPoint(Convert.ToDouble(infoElement.Element("Latitude").Value, CultureInfo.InvariantCulture), Convert.ToDouble(infoElement.Element("Longitude").Value, CultureInfo.InvariantCulture))
						points.Add(geoPoint)
					Next infoElement
					Dim info As 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_Renamed.Add(info)
				Next element
			End If
		End Sub
		Private Sub UpdatePlaneInfo(ByVal planeInfo As PlaneInfo)
			visualizer.SelectedPlane = planeInfo
			airPath_Renamed.Clear()
			If planeInfo IsNot Nothing Then
				planeInfo.UpdateAirPath(airPath_Renamed)
			End If
		End Sub
		Private Sub OnTimedEvent(ByVal source As Object, ByVal e As EventArgs)
			Dim currentTime As DateTime = DateTime.Now
			Dim interval As TimeSpan = currentTime.Subtract(lastTime)
			For Each info As PlaneInfo In planes_Renamed
				If (Not info.IsLanded) Then
					info.CurrentFlightTime += SpeedScale * interval.TotalMilliseconds / mSecPerHour
				End If
			Next info
			lastTime = currentTime
			visualizer.Update()
			RaiseDataChanged()
		End Sub
		Private Sub Dispose(ByVal disposing As Boolean)
			If disposing AndAlso (Not isDisposed) Then
				isDisposed = True
				Me.Stop()
				If timer IsNot Nothing Then
					timer.Dispose()
				End If
				If sourcePlaneIcon IsNot Nothing Then
					sourcePlaneIcon.Dispose()
				End If
			End If
		End Sub
		Public Sub Dispose() Implements IDisposable.Dispose
			Dispose(True)
			GC.SuppressFinalize(Me)
		End Sub
		Public Sub Start()
			lastTime = DateTime.Now
			timer.Start()
		End Sub
		Public Sub [Stop]()
			timer.Stop()
		End Sub
	End Class

	Public Class PlaneInfoVisualizer
		Private selectedPlane_Renamed As PlaneInfo

		Private privateNameLabel As LabelControl
		Public Property NameLabel() As LabelControl
			Get
				Return privateNameLabel
			End Get
			Set(ByVal value As LabelControl)
				privateNameLabel = value
			End Set
		End Property
		Private privateFlightNumberLabel As LabelControl
		Public Property FlightNumberLabel() As LabelControl
			Get
				Return privateFlightNumberLabel
			End Get
			Set(ByVal value As LabelControl)
				privateFlightNumberLabel = value
			End Set
		End Property
		Private privateFromLabel As LabelControl
		Public Property FromLabel() As LabelControl
			Get
				Return privateFromLabel
			End Get
			Set(ByVal value As LabelControl)
				privateFromLabel = value
			End Set
		End Property
		Private privateToLabel As LabelControl
		Public Property ToLabel() As LabelControl
			Get
				Return privateToLabel
			End Get
			Set(ByVal value As LabelControl)
				privateToLabel = value
			End Set
		End Property
		Private privateCurrentTimeLabel As LabelControl
		Public Property CurrentTimeLabel() As LabelControl
			Get
				Return privateCurrentTimeLabel
			End Get
			Set(ByVal value As LabelControl)
				privateCurrentTimeLabel = value
			End Set
		End Property
		Private privateFlightTimeLabel As LabelControl
		Public Property FlightTimeLabel() As LabelControl
			Get
				Return privateFlightTimeLabel
			End Get
			Set(ByVal value As LabelControl)
				privateFlightTimeLabel = value
			End Set
		End Property
		Private privateSpeedLabel As LabelControl
		Public Property SpeedLabel() As LabelControl
			Get
				Return privateSpeedLabel
			End Get
			Set(ByVal value As LabelControl)
				privateSpeedLabel = value
			End Set
		End Property
		Private privateAltitudeLabel As LabelControl
		Public Property AltitudeLabel() As LabelControl
			Get
				Return privateAltitudeLabel
			End Get
			Set(ByVal value As LabelControl)
				privateAltitudeLabel = value
			End Set
		End Property
		Private privatePlaneInfoPanel As PanelControl
		Public Property PlaneInfoPanel() As PanelControl
			Get
				Return privatePlaneInfoPanel
			End Get
			Set(ByVal value As PanelControl)
				privatePlaneInfoPanel = value
			End Set
		End Property
		Private privatePlaneImage As PictureEdit
		Public Property PlaneImage() As PictureEdit
			Get
				Return privatePlaneImage
			End Get
			Set(ByVal value As PictureEdit)
				privatePlaneImage = value
			End Set
		End Property
		Public Property SelectedPlane() As PlaneInfo
			Get
				Return selectedPlane_Renamed
			End Get
			Set(ByVal value As PlaneInfo)
				If selectedPlane_Renamed Is value Then
					Return
				End If
				selectedPlane_Renamed = value
				Update()
			End Set
		End Property

		Public Sub Update()
			If selectedPlane_Renamed Is Nothing Then
				PlaneInfoPanel.Visible = False
				Return
			End If
			PlaneInfoPanel.Visible = True
			NameLabel.Text = selectedPlane_Renamed.Name
			FlightNumberLabel.Text = selectedPlane_Renamed.PlaneID
			FromLabel.Text = selectedPlane_Renamed.StartPointName
			ToLabel.Text = selectedPlane_Renamed.EndPointName
			CurrentTimeLabel.Text = New TimeSpan(0, 0, CInt(Fix(Math.Ceiling(selectedPlane_Renamed.CurrentFlightTime * 3600)))).ToString()
			FlightTimeLabel.Text = New TimeSpan(0, 0, CInt(Fix(Math.Ceiling(selectedPlane_Renamed.TotalFlightTime * 3600)))).ToString()
			SpeedLabel.Text = selectedPlane_Renamed.SpeedKmH.ToString()
			AltitudeLabel.Text = selectedPlane_Renamed.FlightAltitude.ToString()
			PlaneImage.Image = selectedPlane_Renamed.Image
		End Sub
	End Class

	Public Class FlightMapFactory
		Inherits DefaultMapItemFactory
		Protected Overrides Sub InitializeItem(ByVal item As MapItem, ByVal obj As Object)
			MyBase.InitializeItem(item, obj)
			Dim polyLine As MapPolyline = TryCast(item, MapPolyline)
			Dim trajectory As PlaneTrajectory = TryCast(obj, PlaneTrajectory)
			If polyLine IsNot Nothing AndAlso trajectory IsNot Nothing Then
				polyLine.Points = trajectory.GetAirPath()
				polyLine.Fill = Color.Empty
				polyLine.Stroke = Color.FromArgb(127, 255, 0, 199)
				polyLine.StrokeWidth = 4
			End If
		End Sub
	End Class

	Public Class InfoList
		Inherits CollectionBase
		Implements IBindingList
		Private Event listChangedHandler As ListChangedEventHandler

		Default Public ReadOnly Property Item(ByVal idx As Integer) As InfoBase
			Get
				Return CType(MyBase.List(idx), InfoBase)
			End Get
		End Property
		Public ReadOnly Property AllowEdit() As Boolean Implements IBindingList.AllowEdit
			Get
				Return True
			End Get
		End Property
		Public ReadOnly Property AllowNew() As Boolean Implements IBindingList.AllowNew
			Get
				Return False
			End Get
		End Property
		Public ReadOnly Property AllowRemove() As Boolean Implements IBindingList.AllowRemove
			Get
				Return True
			End Get
		End Property

		Public Custom Event ListChanged As ListChangedEventHandler Implements IBindingList.ListChanged
			AddHandler(ByVal value As ListChangedEventHandler)
				AddHandler listChangedHandler, value
			End AddHandler
			RemoveHandler(ByVal value As ListChangedEventHandler)
				RemoveHandler listChangedHandler, value
			End RemoveHandler
			RaiseEvent(ByVal sender As System.Object, ByVal e As System.ComponentModel.ListChangedEventArgs)
			End RaiseEvent
		End Event

		Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
			OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
		End Sub
		Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
			OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
		End Sub
		Friend Sub OnListChanged(ByVal args As ListChangedEventArgs)
			RaiseEvent listChangedHandler(Me, args)
		End Sub
		Protected Overrides Sub OnClearComplete()
			MyBase.OnClearComplete()
			OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
		End Sub
		Public Sub Add(ByVal appointment As InfoBase)
			MyBase.List.Add(appointment)
		End Sub
		Public Function IndexOf(ByVal appointment As InfoBase) As Integer
			Return List.IndexOf(appointment)
		End Function
		Public Function AddNew() As Object Implements IBindingList.AddNew
			Throw New NotSupportedException()
		End Function
		Public Sub AddIndex(ByVal pd As PropertyDescriptor) Implements IBindingList.AddIndex
			Throw New NotSupportedException()
		End Sub
		Public Sub ApplySort(ByVal pd As PropertyDescriptor, ByVal dir As ListSortDirection) Implements IBindingList.ApplySort
			Throw New NotSupportedException()
		End Sub
		Public Function Find(ByVal [property] As PropertyDescriptor, ByVal key As Object) As Integer Implements IBindingList.Find
			Throw New NotSupportedException()
		End Function
		Public ReadOnly Property IsSorted() As Boolean Implements IBindingList.IsSorted
			Get
				Return False
			End Get
		End Property
		Public Sub RemoveIndex(ByVal pd As PropertyDescriptor) Implements IBindingList.RemoveIndex
			Throw New NotSupportedException()
		End Sub
		Public Sub RemoveSort() Implements IBindingList.RemoveSort
			Throw New NotSupportedException()
		End Sub
		Public ReadOnly Property SortDirection() As ListSortDirection Implements IBindingList.SortDirection
			Get
				Throw New NotSupportedException()
			End Get
		End Property
		Public ReadOnly Property SortProperty() As PropertyDescriptor Implements IBindingList.SortProperty
			Get
				Throw New NotSupportedException()
			End Get
		End Property
		Public ReadOnly Property SupportsChangeNotification() As Boolean Implements IBindingList.SupportsChangeNotification
			Get
				Return True
			End Get
		End Property
		Public ReadOnly Property SupportsSearching() As Boolean Implements IBindingList.SupportsSearching
			Get
				Return False
			End Get
		End Property
		Public ReadOnly Property SupportsSorting() As Boolean Implements IBindingList.SupportsSorting
			Get
				Return False
			End Get
		End Property
	End Class
End Namespace