Android Question Fix marker on screen while map rotates (like Google Maps Navigation)

marcick

Well-Known Member
Licensed User
Longtime User
Hi all
I have a GoogleMap with a certain zoom level and bearing. I also have a marker with specific coordinates that must appear visually at 50% of the screen width (horizontally centered) and 25% from the bottom (vertically). The marker represents a moving vehicle, and its position must remain fixed at that exact point on the screen, while the map is allowed to rotate to always show the driving direction, and the zoom level can change freely.

How can I determine, at each location update, the correct CameraPosition to achieve this result?

With a bearing of 0, I managed to get it right, but at other angles, complex trigonometric calculations come into play. After three days of pure madness with ChatGPT, I only got approximate results, not the precise behavior I need.

Is there anyone here with solid expertise in this area?
 

TILogistic

Expert
Licensed User
Longtime User
I don't quite understand what you want, but you should check the CameraPosition parameters.

With this I can always have the scoreboard in the center of the screen.
B4X:
    'LastLocation
    If Not(LastLocation.IsInitialized) Then
        Dim CameraPosition1 = GoogleMaps1.CameraPosition, NewCameraPosition As CameraPosition
        NewCameraPosition.Initialize2(Location1.Latitude, Location1.Longitude, CameraPosition1.Zoom, CameraPosition1.Bearing, CameraPosition1.Tilt)
        GoogleMaps1.AnimateCamera(NewCameraPosition)
        LastLocation = Location1
    End If

or indicate with a drawing what you want to do, to have an idea of what you want.
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
Yes.
Have in mind the icon of a navigator app?
The marker should appear always in this fixed positio, centered in horizontal and at 25% of the screen height from the bottom.
With map bearing of 0 it's easy to shift an amount of latitude, but the map must be oriented in the direction of travel and with other bearing (and with some degree of tilt also) it become difficult to evaluate how much shift latitude and longitude also. I’ve already achieved some results, but the position isn’t accurate — it deviates from the ideal depending on bearing and zoom. Visually, it’s quite annoying.

1748156044800.png


This is the code I've obtained with help of ChatGpt:

B4X:
Dim gpsLatLng As LatLng = mo.Marker.Position
Dim jo As JavaObject = gmap
Dim projection As JavaObject = jo.RunMethod("getProjection", Null)
Dim visibleRegion As JavaObject = projection.RunMethod("getVisibleRegion", Null)
Dim latLngBounds As JavaObject = visibleRegion.GetField("latLngBounds")
Dim southwest As JavaObject = latLngBounds.GetField("southwest")
Dim northeast As JavaObject = latLngBounds.GetField("northeast")
Dim minLat As Double = southwest.GetField("latitude")
Dim maxLat As Double = northeast.GetField("latitude")
Dim bearing As Float = mo.Course
Dim LatSpan25 As Double = (maxLat - minLat) * 0.25
Dim angleRad As Double = bearing * (cPI / 180)
Dim EarthRadius As Double = 6378137
Dim MeterPerDegreeLat As Double = (cPI / 180) * EarthRadius
Dim MeterPerDegreeLng As Double = MeterPerDegreeLat * Cos(gpsLatLng.Latitude * (cPI / 180))
Dim LatSpan25Meters As Double = LatSpan25 * MeterPerDegreeLat
Dim LngSpanCompensated As Double = LatSpan25Meters / MeterPerDegreeLng
Dim newLatOffset As Double = LatSpan25 * Cos(angleRad)
Dim newLngOffset As Double = LngSpanCompensated * Sin(angleRad)
Dim newLat As Double = gpsLatLng.Latitude + newLatOffset
Dim newLng As Double = gpsLatLng.Longitude + newLngOffset
Dim cp As CameraPosition
cp.Initialize2(newLat, newLng, zoomLevel, bearing, 60)
gmap.animatecamera(cp)
 

Attachments

  • 1748155616849.png
    1748155616849.png
    506.9 KB · Views: 68
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
Solved.
I worked through the logic in my head, which seemed correct to me, then I submitted it to ChatGPT and it gave me this code that works perfectly.
The invisible map has the same identical size of the working map and is only used to avoid seeing a double animation.
The result can be used as the new cameraposition of the working map and it's absolutely perfect !

B4X:
Sub GetLatLngAt25PercentFromBottom(markerPos As LatLng, zoom As Float, bearing As Float) As ResumableSub
    ' Step 1: center the invisible map on the marker with the given bearing and zoom
    Dim cp As CameraPosition
    cp.Initialize2(markerPos.Latitude, markerPos.Longitude, zoom, bearing, 0)
    gmapcalc.MoveCamera(cp)
    ' Step 2: wait until the invisible map has finished moving
    Wait For (WaitMapIdle) Complete (ok As Boolean)
    ' Step 3: calculate the screen coordinates of the point at 25% from the bottom
    Dim mapWidth As Int = PnlMapCalc.Width ' panels containing the invisible map
    Dim mapHeight As Int = PnlMapCalc.Height
    Dim screenX As Int = mapWidth / 2
    Dim screenY As Int = mapHeight * 0.25
    Dim joMap As JavaObject = gmapcalc
    Dim projection As JavaObject = joMap.RunMethod("getProjection", Null)
    Dim pointClass As JavaObject
    pointClass.InitializeNewInstance("android.graphics.Point", Array(screenX, screenY))
    Dim targetLatLng As JavaObject = projection.RunMethod("fromScreenLocation", Array(pointClass))
    Dim result As LatLng
    result.Initialize(targetLatLng.GetField("latitude"), targetLatLng.GetField("longitude"))
    Return result
End Sub
 
Upvote 0
Top