Mini Kabibi Habibi

Current Path : C:/Users/Public/Documents/DXperience 13.1 Demos/WPF/VB/MapDemo.Wpf/InfromationLayer/
Upload File :
Current File : C:/Users/Public/Documents/DXperience 13.1 Demos/WPF/VB/MapDemo.Wpf/InfromationLayer/DriveModel.vb

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Threading
Imports DevExpress.Xpf.Map
Imports DevExpress.Xpf.Map.Native

Namespace MapDemo
	Public Class DriveModel
		Inherits NavigatorDataModel
		Private Const driveSpeed As Double = 100.0
		Private Const driveTicksPerSecond As Double = 100
		Private Const driveTimeQuant As Double = 1 / driveTicksPerSecond

		Private drivePushpin As MapPushpin
		Private drivePath As MapPolyline
		Private parentModel As RouteModel
		Private routePath As List(Of GeoPoint)
		Private routeNodeIndex As Integer
		Private baseLocation As GeoPoint
		Private targetLocation As GeoPoint
		Private basePoint As MapUnit
		Private targetPoint As MapUnit
		Private distance As Double
		Private currentDistance As Double
		Private currentPoint As MapUnit
		Private itineraryItems As List(Of BingItineraryItem)
		Private routePushpins As List(Of MapPushpin)
		Private animationTimer_Renamed As DispatcherTimer
		Private actionText_Renamed As String

		Private privateDriveItems As ObservableCollection(Of MapItem)
		Public Property DriveItems() As ObservableCollection(Of MapItem)
			Get
				Return privateDriveItems
			End Get
			Private Set(ByVal value As ObservableCollection(Of MapItem))
				privateDriveItems = value
			End Set
		End Property
		Public Property ActionText() As String
			Get
				Return Me.actionText_Renamed
			End Get
			Set(ByVal value As String)
				If Me.actionText_Renamed <> value Then
					Me.actionText_Renamed = value
					NotifyPropertyChanged("ActionText")
					parentModel.NotifyDriveModelChanged()
				End If
			End Set
		End Property
		Public ReadOnly Property CurrentLocation() As GeoPoint
			Get
				Return parentModel.Navigator.RouteLayer.MapUnitToGeoPoint(currentPoint)
			End Get
		End Property

		Public Shared Function DistanceBetweenPoints(ByVal a As MapUnit, ByVal b As MapUnit) As Double
			Dim vector As New MapUnit(b.X - a.X, b.Y - a.Y)
			Return Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y)
		End Function
		Public Shared Function KilometerPerHourToMapUnitsPerSecond(ByVal kmh As Double) As Double
			Return kmh / 40000.0 / 360.0
		End Function

		Public Sub New(ByVal parentModel As RouteModel)
			Me.parentModel = parentModel
			routePath = parentModel.RoutePath
			itineraryItems = New List(Of BingItineraryItem)()
			itineraryItems.AddRange(parentModel.ItineraryItems)
			routePushpins = New List(Of MapPushpin)()
			routePushpins.AddRange(parentModel.RoutePushpins)

			drivePushpin = New MapPushpin()
			drivePushpin.Location = routePath(0)
			drivePushpin.MarkerTemplate = parentModel.Navigator.DriveMarkerTemplate
			drivePath = New MapPolyline()
			drivePath.Stroke = parentModel.Navigator.DriveBrush
			drivePath.StrokeStyle = New StrokeStyle() With {.Thickness = 4, .StartLineCap = PenLineCap.Round, .EndLineCap = PenLineCap.Round}
			drivePath.Points.Add(targetLocation)
			targetLocation = routePath(0)

			DriveItems = New ObservableCollection(Of MapItem)()
			DriveItems.Add(drivePath)
			DriveItems.Add(drivePushpin)

			Me.animationTimer_Renamed = New DispatcherTimer()
			Me.animationTimer_Renamed.Interval = TimeSpan.FromSeconds(driveTimeQuant)
			AddHandler animationTimer_Renamed.Tick, AddressOf AnimationTimer

			Advance()
		End Sub

		Private Sub CheckItinerary()
			Dim routeLayer As InformationLayer = parentModel.Navigator.RouteLayer
			Dim location As GeoPoint = routeLayer.MapUnitToGeoPoint(currentPoint)
			Dim currentItem As BingItineraryItem = itineraryItems(0)
			Dim geoSize As New Size(Math.Abs(location.Latitude - currentItem.Location.Latitude), Math.Abs(location.Longitude - currentItem.Location.Longitude))
			Dim metricSize As Size = routeLayer.GeoToKilometersSize(location, geoSize)
			Dim distance As Double = Math.Sqrt(metricSize.Width * metricSize.Width + metricSize.Height * metricSize.Height)
			If distance < 0.005 Then
				If itineraryItems.Count > 1 Then
					itineraryItems.Remove(currentItem)
				Else
					distance = 0.0
				End If
			End If
			If distance > 0.0 Then
				ActionText = CommonUtils.GetUserFriendlyEnumString(itineraryItems(0).Maneuver) & " after " & (If((distance > 0.9), String.Format("{0:0} km", Math.Ceiling(distance)), String.Format("{0:0} m", Math.Ceiling(distance * 10) * 100)))
			Else
				ActionText = "Finish! Click Stop and Clear to set a new route."
			End If
		End Sub
		Private Sub CheckRoutePushpins(ByVal location As GeoPoint)
			For Each pushpin As MapPushpin In routePushpins
				If (Math.Abs(pushpin.Location.Latitude - location.Latitude) < 0.00001) AndAlso (Math.Abs(pushpin.Location.Longitude - location.Longitude) < 0.00001) Then
					pushpin.Brush = parentModel.Navigator.DriveBrush
				End If
			Next pushpin
		End Sub
		Private Function Advance() As Boolean
			If routeNodeIndex < (routePath.Count - 1) Then
				routeNodeIndex += 1
				Dim routeLayer As InformationLayer = parentModel.Navigator.RouteLayer
				baseLocation = targetLocation
				currentPoint = routeLayer.GeoPointToMapUnit(baseLocation)
				targetLocation = routePath(routeNodeIndex)
				basePoint = routeLayer.GeoPointToMapUnit(baseLocation)
				targetPoint = routeLayer.GeoPointToMapUnit(targetLocation)
				distance = DriveModel.DistanceBetweenPoints(targetPoint, basePoint)
				currentDistance = 0

				drivePath.Points(drivePath.Points.Count - 1) = baseLocation
				drivePath.Points.Add(baseLocation)

				CheckItinerary()
				CheckRoutePushpins(baseLocation)

				If (Not animationTimer_Renamed.IsEnabled) Then
					animationTimer_Renamed.Start()
				End If
				Return True
			Else
				If routePushpins.Count > 0 Then
					routePushpins(routePushpins.Count - 1).Brush = parentModel.Navigator.DriveBrush
				End If
				If animationTimer_Renamed.IsEnabled Then
					animationTimer_Renamed.Stop()
				End If
				drivePushpin.Visible = False
				Return False
			End If
		End Function
		Private Sub AnimationTimer(ByVal sender As Object, ByVal e As EventArgs)
			Dim scaledTime As Double = driveTimeQuant * parentModel.TimeScale
			Do While scaledTime > 0.0
				Dim quant As Double = Math.Min(scaledTime, driveTimeQuant)
				Dim excess As Double = Update(quant * DriveModel.KilometerPerHourToMapUnitsPerSecond(driveSpeed))
				If excess > 0.0 Then
					If (Not Advance()) Then
						CheckItinerary()
						PlaceItems()
						Return
					End If
					excess = Update(excess)
				End If
				PlaceItems()
				CheckItinerary()
				scaledTime -= quant
			Loop
		End Sub
		Private Sub PlaceItems()
			PlaceItems(parentModel.Navigator.RouteLayer.MapUnitToGeoPoint(currentPoint))
			NotifyPropertyChanged("CurrentLocation")
		End Sub
		Private Sub PlaceItems(ByVal location As GeoPoint)
			drivePath.Points(drivePath.Points.Count - 1) = location
			drivePushpin.Location = location
		End Sub
		Private Function GetDirection() As MapUnit
			Dim direction As New MapUnit(targetPoint.X - basePoint.X, targetPoint.Y - basePoint.Y)
			Dim length As Double = Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y)
			If length > 0.0 Then
				Dim oneByLenght As Double = 1 / length
				direction.X *= oneByLenght
				direction.Y *= oneByLenght
			End If
			Return direction
		End Function
		Private Function Update(ByVal distanceToGo As Double) As Double
			currentDistance += distanceToGo
			If currentDistance > distance Then
				currentPoint = targetPoint
				Return currentDistance - distance
			End If
			Dim offset As MapUnit = GetDirection()
			offset.X *= currentDistance
			offset.Y *= currentDistance
			currentPoint = New MapUnit(basePoint.X + offset.X, basePoint.Y + offset.Y)
			Return 0.0
		End Function

		Public Sub Cleanup()
			For Each pushpin As MapPushpin In routePushpins
				pushpin.Brush = parentModel.Navigator.DefaultBrush
			Next pushpin
			If animationTimer_Renamed.IsEnabled Then
				animationTimer_Renamed.Stop()
			End If
		End Sub
	End Class
End Namespace