Code:
Option Explicit
Dim ma As Object
Dim view_X As Double, view_Y As Double, view_Z As Double
Dim dView_X As Double, dView_Y As Double, dView_Z As Double
Dim aim_view_z As Double
Dim fade As Single
Dim fade_rate As Single
Private Const default_fade_rate = 0.2
Private Const Min_Zoom = 4
Private Const Max_Zoom = 21
Private Const aim_view_step = 0.1
Private Const Dynamic_Map_Sizing = True
Private Const menuSizeX = 300
Private Const menuSizeY = 170
Private Const menuSizeShortY = 90
Private Const border = 10
Private Const inner_border = 15
Private Const title_border = border + inner_border
Dim map_cache As New dictionary
Private Const pi = 3.14159265358979
Private Const r = 6378.1
Private Const mercRatioX As Double = 6.38011715438025E-03
Private Const mercRatioY As Double = 6.38532710916024E-03
Private Const scrollborder = 10
Dim snap_location As Boolean, snap_zoom As Boolean
Private Type mappos
X As Double
Y As Double
zoom As Double
End Type
Private Type sRECT
Left As Single
Top As Single
Right As Single
Bottom As Single
End Type
Private Const text_height = 35
Private Const icon_size = 32
Private Const car_glow = "jpg/carlight.jpg"
Private Const car_icon = "jpg/caricon.jpg"
Private Const default_car_fade_rate = 4
Dim car_fade_rate As Long
Dim car_fade_stage As Long
Private Const back_arrow = "jpg/backarrow.jpg"
Private Const back_arrow_size = 60
Private Const back_border_x = 20
Private Const back_border_y = 30
Dim themeDarkR As Long, themeDarkG As Long, themeDarkB As Long
Dim themeR As Long, themeG As Long, themeB As Long
Dim clicked As Boolean, clickX As Single, clickY As Single
Dim menuShowTimeout As Long, menuShowTimeout_rate As Long
Private Const menuShowTimeout_Max = 500
Private Const menuShowTimeout_MinShow = 50
Dim settings As Object
Private Const zoom_panel_x = 206
Private Const zoom_panel_y = 70
Dim cGrammar As New Collection
Dim lastMove As Integer
Public Property Get icon() As String
icon = "jpg/maps-320.jpg"
End Property
Public Property Get caption() As String
caption = "Maps"
End Property
Public Property Get ClassName() As String
ClassName = "CarPC.Maps"
End Property
Sub Class_Load()
Set settings = CreateObject("CarPC.Settings")
settings.loadfile TypeName(Me)
Set ma = CreateObject("CarPC.MapAid")
ma.Init
If Val(settings.var("GPS_Enabled")) = 1 Then
ma.connectGPS Val(settings.var("GPS_Port")), Val(settings.var("GPS_Baud"))
End If
themeDarkR = Val(settings.var("themeDarkR"))
themeDarkG = Val(settings.var("themeDarkG"))
themeDarkB = Val(settings.var("themeDarkB"))
themeR = Val(settings.var("themeR"))
themeG = Val(settings.var("themeG"))
themeB = Val(settings.var("themeB"))
view_X = Val(settings.var("longitude"))
view_Y = Val(settings.var("latitude"))
view_Z = Val(settings.var("zoom"))
cGrammar.Add "Locate"
cGrammar.Add "Zoom in"
cGrammar.Add "Zoom out"
cGrammar.Add "Pan left"
cGrammar.Add "Pan right"
cGrammar.Add "Pan up"
cGrammar.Add "Pan down"
cGrammar.Add "More"
cGrammar.Add "Max"
cGrammar.Add "Menu"
End Sub
Public Property Get grammar() As Collection
Set grammar = cGrammar
End Property
Sub Class_KeyDown(windows As Object, keycode As Integer)
If keycode = 27 Or keycode = 8 Then
windows.moveClassDown Me
settings.savefile
End If
If keycode = 189 Then
dView_Z = dView_Z - 0.05
snap_zoom = False
End If
If keycode = 187 Then
dView_Z = dView_Z + 0.05
snap_zoom = False
End If
If keycode = 37 Then
dView_X = dView_X - 10
snap_location = False
End If
If keycode = 39 Then
dView_X = dView_X + 10
snap_location = False
End If
If keycode = 38 Then
dView_Y = dView_Y + 10
snap_location = False
End If
If keycode = 40 Then
dView_Y = dView_Y - 10
snap_location = False
End If
If keycode = 13 Then
snap_location = True
snap_zoom = True
If Not ma.gpsEnabled Then
If Val(settings.var("GPS_Enabled")) = 1 Then
ma.connectGPS Val(settings.var("GPS_Port")), Val(settings.var("GPS_Baud"))
End If
End If
menuShowTimeout_rate = 2
End If
End Sub
Sub Class_blt(windows As Object, graphics As Object)
If windows.getLeadingWindow Is Me Then
fade_rate = default_fade_rate
Else
fade_rate = -default_fade_rate
End If
fade = fade + fade_rate
If fade < 0 Then fade = 0
If fade > 1 Then fade = 1
If fade > 0 Then
If ma.satelites >= 3 And snap_location Then
view_X = ma.longitude
view_Y = ma.latitude
End If
If ma.satelites >= 7 And snap_zoom Then
If ma.speed > 150 Then
aim_view_z = 13
ElseIf ma.speed > 100 And ma.speed < 140 Then
aim_view_z = 14
ElseIf ma.speed > 70 And ma.speed < 90 Then
aim_view_z = 15
ElseIf ma.speed > 40 And ma.speed < 60 Then
aim_view_z = 16
ElseIf ma.speed < 30 And ma.speed > 10 Then
aim_view_z = 17
Else
aim_view_z = 15
End If
Else
aim_view_z = 0
End If
If dView_X <> 0 Or dView_Y <> 0 Then
Dim pt As mappos
pt.X = view_X
pt.Y = view_Y
pt.zoom = view_Z
pt = radialToPixel(pt)
pt.X = pt.X + dView_X
pt.Y = pt.Y + dView_Y
pt = pixelToRadial(pt)
view_X = pt.X
view_Y = pt.Y
End If
If dView_Z <> 0 Then view_Z = view_Z + dView_Z
dView_X = dView_X * 0.92
dView_Y = dView_Y * 0.92
dView_Z = dView_Z * 0.92
If Abs(dView_X) < 0.001 Then dView_X = 0
If Abs(dView_Y) < 0.001 Then dView_Y = 0
If Abs(dView_Z) < 0.001 Then dView_Z = 0
If aim_view_z > 0 Then
If aim_view_z > view_Z Then
view_Z = view_Z + aim_view_step
End If
If aim_view_z < view_Z Then
view_Z = view_Z - aim_view_step
End If
If Abs(aim_view_z - view_Z) < aim_view_step Then view_Z = aim_view_z
End If
If view_Z > Max_Zoom Then view_Z = Max_Zoom
If view_Z < Min_Zoom Then view_Z = Min_Zoom
Dim use_zoom As Long
use_zoom = floor(view_Z)
Dim rendered As Boolean, insufficient_map_data As Boolean
Do Until rendered Or use_zoom < Min_Zoom
Dim render_width As Double, render_height As Double
render_width = graphics.resX * (2 ^ view_Z / 2 ^ (use_zoom))
render_height = graphics.resY * (2 ^ view_Z / 2 ^ (use_zoom))
Dim px As mappos
px.X = view_X
px.Y = view_Y
px.zoom = use_zoom
px = radialToPixel(px)
Dim phase As mappos
phase.X = px.X
phase.Y = px.Y
px.X = Round(px.X / ma.store_width) * ma.store_width
px.Y = Round(px.Y / ma.store_height) * ma.store_height
phase.X = (phase.X - px.X) / ma.store_width * graphics.resX
phase.Y = (phase.Y - px.Y) / ma.store_height * graphics.resY
Dim maps(0 To 3) As mappos, map_path(0 To 3) As String
maps(0).X = px.X - ma.store_width / 2
maps(0).Y = px.Y + ma.store_height / 2
maps(1).X = px.X + ma.store_width / 2
maps(1).Y = px.Y + ma.store_height / 2
maps(2).X = px.X - ma.store_width / 2
maps(2).Y = px.Y - ma.store_height / 2
maps(3).X = px.X + ma.store_width / 2
maps(3).Y = px.Y - ma.store_height / 2
Dim i As Long
Dim drawPoints(0 To 3) As sRECT
drawPoints(0).Left = graphics.resX / 2 - phase.X - graphics.resX
drawPoints(0).Top = graphics.resY / 2 + phase.Y - graphics.resY
drawPoints(0).Right = graphics.resX / 2 - phase.X + graphics.resX - graphics.resX
drawPoints(0).Bottom = graphics.resY / 2 + phase.Y + graphics.resY - graphics.resY
drawPoints(1).Left = graphics.resX / 2 - phase.X
drawPoints(1).Top = graphics.resY / 2 + phase.Y - graphics.resY
drawPoints(1).Right = graphics.resX / 2 - phase.X + graphics.resX
drawPoints(1).Bottom = graphics.resY / 2 + phase.Y + graphics.resY - graphics.resY
drawPoints(2).Left = graphics.resX / 2 - phase.X - graphics.resX
drawPoints(2).Top = graphics.resY / 2 + phase.Y
drawPoints(2).Right = graphics.resX / 2 - phase.X + graphics.resX - graphics.resX
drawPoints(2).Bottom = graphics.resY / 2 + phase.Y + graphics.resY
drawPoints(3).Left = graphics.resX / 2 - phase.X
drawPoints(3).Top = graphics.resY / 2 + phase.Y
drawPoints(3).Right = graphics.resX / 2 - phase.X + graphics.resX
drawPoints(3).Bottom = graphics.resY / 2 + phase.Y + graphics.resY
insufficient_map_data = False
Dim mC As String
For i = 0 To 3
maps(i).zoom = use_zoom
maps(i) = pixelToRadial(maps(i))
mC = map_cache.Item(maps(i).X & "," & maps(i).Y & "," & use_zoom)
If mC <> "" Then
map_path(i) = mC
Else
map_path(i) = ma.getMap(maps(i).X, maps(i).Y, use_zoom)
End If
drawPoints(i).Top = (drawPoints(i).Top - graphics.resY / 2) / 2 ^ use_zoom * 2 ^ view_Z + graphics.resY / 2
drawPoints(i).Bottom = (drawPoints(i).Bottom - graphics.resY / 2) / 2 ^ use_zoom * 2 ^ view_Z + graphics.resY / 2
drawPoints(i).Left = (drawPoints(i).Left - graphics.resX / 2) / 2 ^ use_zoom * 2 ^ view_Z + graphics.resX / 2
drawPoints(i).Right = (drawPoints(i).Right - graphics.resX / 2) / 2 ^ use_zoom * 2 ^ view_Z + graphics.resX / 2
If map_path(i) = "" Then
insufficient_map_data = True
Else
map_cache.Item(maps(i).X & "," & maps(i).Y & "," & use_zoom) = map_path(i)
End If
Next
insufficient_map_data = insufficient_map_data And Dynamic_Map_Sizing
If Not insufficient_map_data Then
rendered = True
For i = 0 To 3
graphics.BitBlt map_path(i), drawPoints(i).Left, drawPoints(i).Top, drawPoints(i).Right, drawPoints(i).Bottom, fade * 255, fade * 255, fade * 255
Next
Else
use_zoom = use_zoom - 1
End If
Loop
If ma.satelites >= 3 Then
Dim iconLocation As mappos
Dim mapLocation As mappos
iconLocation.X = ma.longitude
iconLocation.Y = ma.latitude
iconLocation.zoom = view_Z
mapLocation.X = view_X
mapLocation.Y = view_Y
mapLocation.zoom = view_Z
iconLocation = radialToPixel(iconLocation)
mapLocation = radialToPixel(mapLocation)
graphics.BitBlt car_glow, graphics.resX / 2 + (-mapLocation.X + iconLocation.X) * graphics.resX / ma.store_width - icon_size, _
graphics.resY / 2 + (mapLocation.Y - iconLocation.Y) * graphics.resY / ma.store_height - icon_size, _
graphics.resX / 2 + (-mapLocation.X + iconLocation.X) * graphics.resX / ma.store_width + icon_size, _
graphics.resY / 2 + (mapLocation.Y - iconLocation.Y) * graphics.resY / ma.store_height + icon_size, _
themeR * car_fade_stage / 255, themeG * car_fade_stage / 255, themeB * car_fade_stage / 255
graphics.BitBlt car_icon, graphics.resX / 2 + (-mapLocation.X + iconLocation.X) * graphics.resX / ma.store_width - icon_size / 2, _
graphics.resY / 2 + (mapLocation.Y - iconLocation.Y) * graphics.resY / ma.store_height - icon_size / 2, _
graphics.resX / 2 + (-mapLocation.X + iconLocation.X) * graphics.resX / ma.store_width + icon_size / 2, _
graphics.resY / 2 + (mapLocation.Y - iconLocation.Y) * graphics.resY / ma.store_height + icon_size / 2, _
255, 255, 255
car_fade_stage = car_fade_stage + car_fade_rate
If car_fade_stage <= 0 Then
car_fade_stage = 0
car_fade_rate = default_car_fade_rate
ElseIf car_fade_stage >= 255 Then
car_fade_stage = 255
car_fade_rate = -default_car_fade_rate
End If
End If
Dim y_phase As Single, y_fade As Single
menuShowTimeout = menuShowTimeout + menuShowTimeout_rate
If menuShowTimeout >= menuShowTimeout_Max Then
menuShowTimeout_rate = -2
ElseIf menuShowTimeout <= 0 Then
menuShowTimeout_rate = 0
End If
y_phase = menuShowTimeout / menuShowTimeout_MinShow
If y_phase > 1 Then y_phase = 1
y_fade = y_phase
y_phase = graphics.resY * (1 - y_phase)
Dim back_button_phase As Long
If (windows.input_type And 2) Or (windows.input_type And 8) Then
back_button_phase = back_arrow_size + border
End If
If Not ma.gpsEnabled Then
graphics.BitBlt "jpg/maps-menu-short.jpg", border, border + border - y_phase, border + menuSizeX, menuSizeShortY + border - y_phase, themeR, themeG, themeB
If (windows.input_type And 2) Or (windows.input_type And 8) Then
graphics.BitBlt back_arrow, back_border_x, back_border_y - y_phase, back_border_x + back_arrow_size, back_border_y + back_arrow_size - y_phase, themeR, themeG, themeB
End If
graphics.bltText "No GPS Detected", back_border_x + border + back_button_phase, back_border_y - y_phase + back_arrow_size + border - text_height * 2, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border - text_height, vbAlignLeft, themeR, themeG, themeB
ElseIf ma.satelites = 0 Then
graphics.BitBlt "jpg/maps-menu-short.jpg", border, border + border - y_phase, border + menuSizeX, menuSizeShortY + border - y_phase, themeR, themeG, themeB
If (windows.input_type And 2) Or (windows.input_type And 8) Then
graphics.BitBlt back_arrow, back_border_x, back_border_y - y_phase, back_border_x + back_arrow_size, back_border_y + back_arrow_size - y_phase, themeR, themeG, themeB
End If
graphics.bltText "No GPS Signal", back_border_x + border + back_button_phase, back_border_y - y_phase + back_arrow_size + border - text_height * 2, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border - text_height, vbAlignLeft, themeR, themeG, themeB
Else
graphics.BitBlt "jpg/maps-menu.jpg", border, border + border - y_phase, border + menuSizeX, menuSizeY + border - y_phase, themeR, themeG, themeB
If (windows.input_type And 2) Or (windows.input_type And 8) Then
graphics.BitBlt back_arrow, back_border_x, back_border_y - y_phase, back_border_x + back_arrow_size, back_border_y + back_arrow_size - y_phase, themeR, themeG, themeB
End If
graphics.bltText "Longitude: ", back_border_x + border, back_border_y - y_phase + back_arrow_size + border, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height, vbAlignLeft, themeR, themeG, themeB
graphics.bltText "Latitude: ", back_border_x + border, back_border_y - y_phase + back_arrow_size + border + text_height, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height * 2, vbAlignLeft, themeR, themeG, themeB
graphics.bltText "" & formatDegree(ma.longitude), back_border_x + border, back_border_y - y_phase + back_arrow_size + border, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height, vbAlignRight, themeR, themeG, themeB
graphics.bltText "" & formatDegree(ma.latitude), back_border_x + border, back_border_y - y_phase + back_arrow_size + border + text_height, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height * 2, vbAlignRight, themeR, themeG, themeB
graphics.bltText "Speed: ", back_border_x + border + back_button_phase, back_border_y - y_phase + back_arrow_size + border - text_height, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height * 0, vbAlignLeft, themeR, themeG, themeB
graphics.bltText "" & Round(ma.speed) & " kph", back_border_x + border + back_arrow_size + border, back_border_y - y_phase + back_arrow_size + border - text_height, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border + text_height * 0, vbAlignRight, themeR, themeG, themeB
graphics.bltText "Satelites: ", back_border_x + border + back_button_phase, back_border_y - y_phase + back_arrow_size + border - text_height * 2, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border - text_height, vbAlignLeft, themeR, themeG, themeB
graphics.bltText "" & ma.satelites, back_border_x + border + back_arrow_size + border, back_border_y - y_phase + back_arrow_size + border - text_height * 2, back_border_x - 2 * border + menuSizeX, back_border_y - y_phase + back_arrow_size + border - text_height, vbAlignRight, themeR, themeG, themeB
End If
If (windows.input_type And 2) Or (windows.input_type And 8) Then
graphics.BitBlt "jpg/zoom.jpg", graphics.resX - zoom_panel_x - border - border, border + border - y_phase, graphics.resX - border - border, zoom_panel_y + border + border - y_phase, themeR, themeG, themeB
End If
graphics.BitBlt "jpg/map-scroll-up.jpg", 0, 0, graphics.resX, scrollborder, themeR * y_fade, themeG * y_fade, themeB * y_fade
graphics.BitBlt "jpg/map-scroll-down.jpg", 0, graphics.resY - scrollborder, graphics.resX, graphics.resY, themeR * y_fade, themeG * y_fade, themeB * y_fade
graphics.BitBlt "jpg/map-scroll-left.jpg", 0, 0, scrollborder, graphics.resY, themeR * y_fade, themeG * y_fade, themeB * y_fade
graphics.BitBlt "jpg/map-scroll-right.jpg", graphics.resX - scrollborder, 0, graphics.resX, graphics.resY, themeR * y_fade, themeG * y_fade, themeB * y_fade
If clicked Then
If distance(back_border_x + back_arrow_size / 2, back_border_y + back_arrow_size / 2, graphics.resX * clickX, graphics.resY * clickY) < back_arrow_size / 2 Then
Class_KeyDown windows, 27
End If
If distance(graphics.resX - zoom_panel_x + back_arrow_size / 2 - border - 3 + 132, border * 2 + 5 - y_phase + back_arrow_size / 2, graphics.resX * clickX, graphics.resY * clickY) < back_arrow_size / 2 Then
Class_KeyDown windows, 13
End If
If distance(graphics.resX - zoom_panel_x + back_arrow_size / 2 - border - 3 + 66, border * 2 + 5 - y_phase + back_arrow_size / 2, graphics.resX * clickX, graphics.resY * clickY) < back_arrow_size / 2 Then
Class_KeyDown windows, 189
End If
If distance(graphics.resX - zoom_panel_x + back_arrow_size / 2 - border - 3, border * 2 + 5 - y_phase + back_arrow_size / 2, graphics.resX * clickX, graphics.resY * clickY) < back_arrow_size / 2 Then
Class_KeyDown windows, 187
End If
If graphics.resX * clickX <= scrollborder Then
Class_KeyDown windows, 37
End If
If graphics.resY * clickY <= scrollborder Then
Class_KeyDown windows, 38
End If
If graphics.resX * clickX >= graphics.resX - scrollborder Then
Class_KeyDown windows, 39
End If
If graphics.resY * clickY >= graphics.resY - scrollborder Then
Class_KeyDown windows, 40
End If
clickX = 0
clickY = 0
clicked = False
End If
End If
settings.var("longitude") = view_X
settings.var("latitude") = view_Y
settings.var("zoom") = view_Z
End Sub
Private Function distance(x1 As Single, y1 As Single, x2 As Single, y2 As Single) As Single
distance = Sqr((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
End Function
Private Function floor(v As Double) As Double
floor = Round(v - 0.49)
End Function
Private Function radialToPixel(pos As mappos) As mappos
radialToPixel.X = ((pos.X - 85) / 180 * pi) * r * (2 ^ pos.zoom) * mercRatioX
radialToPixel.Y = r * Log(((1 + Sin(pos.Y / 180 * pi)) / Cos(pos.Y / 180 * pi))) * (2 ^ pos.zoom) * mercRatioY
radialToPixel.zoom = pos.zoom
End Function
Private Function pixelToRadial(pos As mappos) As mappos
pixelToRadial.X = (pos.X / mercRatioX) / (2 ^ pos.zoom) / r * 180 / pi + 85
pixelToRadial.Y = (2 * Atn(Exp(pos.Y / r / (2 ^ pos.zoom) / mercRatioY)) - pi / 2) * 180 / pi
pixelToRadial.zoom = pos.zoom
End Function
Sub Class_Click(windows As Object, X As Single, Y As Single)
clickX = X
clickY = Y
clicked = True
menuShowTimeout_rate = 2
End Sub
Sub Class_Speak(windows As Object, phrase As String)
If phrase = "Locate" Then
Class_KeyDown windows, 13
lastMove = 0
ElseIf phrase = "Menu" Then
Class_KeyDown windows, 8
lastMove = 0
ElseIf phrase = "Zoom in" Then
Class_KeyDown windows, 187
lastMove = 187
ElseIf phrase = "Zoom out" Then
Class_KeyDown windows, 189
lastMove = 189
ElseIf phrase = "Pan left" Then
Class_KeyDown windows, 37
lastMove = 37
ElseIf phrase = "Pan right" Then
Class_KeyDown windows, 39
lastMove = 39
ElseIf phrase = "Pan up" Then
Class_KeyDown windows, 38
lastMove = 38
ElseIf phrase = "Pan down" Then
Class_KeyDown windows, 40
lastMove = 40
ElseIf phrase = "More" Then
If lastMove > 0 Then Class_KeyDown windows, lastMove
ElseIf phrase = "Max" Then
If lastMove = 187 Then
dView_Z = dView_Z + 1
snap_zoom = False
ElseIf lastMove = 189 Then
dView_Z = dView_Z - 1
snap_zoom = False
End If
End If
End Sub
It's designed to be simple enough that anyone can program classes for it, with classes being able to be completely independent (they can even exist in separate executables) with event calls for various user input such as touchscreen, keyboard and speech with Class_Click, Class_KeyDown and Class_Speak plus a blt call for painting refreshes.
Bookmarks