@@ -17,39 +17,104 @@ import com.google.android.gms.maps.model.VisibleRegion
1717import com.huawei.hms.maps.Projection
1818import org.microg.gms.maps.hms.utils.toGms
1919import org.microg.gms.maps.hms.utils.toHms
20+ import kotlin.math.roundToInt
2021
21- private const val TAG = " GmsMapProjection"
22-
23- class ProjectionImpl (private val projection : Projection ) : IProjectionDelegate.Stub() {
22+ private const val TAG = " GmsProjectionImpl"
2423
24+ class ProjectionImpl (private var projection : Projection , private var withoutTiltOrBearing : Boolean ) : IProjectionDelegate.Stub() {
2525 private var lastVisibleRegion: VisibleRegion ? = null
26+ private var visibleRegion = projection.visibleRegion
27+
28+ private var farLeft: Point ? = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
29+ private var farRight: Point ? = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
30+ private var nearLeft: Point ? = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }
31+
32+ private var farLeftLat = visibleRegion.farLeft?.latitude ? : 0.0
33+ private var nearLeftLat = visibleRegion.nearLeft?.latitude ? : 0.0
34+ private var farLeftLng = visibleRegion.farLeft?.longitude ? : 0.0
35+ private var farRightLng = visibleRegion.farRight?.longitude ? : 0.0
36+ private var farLeftX = farLeft?.x ? : 0
37+ private var farLeftY = farLeft?.y ? : 0
38+ private var farRightX = farRight?.x ? : (farLeftX + 1 )
39+ private var nearLeftY = nearLeft?.y ? : (farLeftY + 1 )
40+
41+ fun updateProjectionState (newProjection : Projection , useFastMode : Boolean ) {
42+ Log .d(TAG , " updateProjectionState: useFastMode: $useFastMode " )
43+ projection = newProjection
44+ visibleRegion = newProjection.visibleRegion
45+ withoutTiltOrBearing = useFastMode
46+
47+ farLeft = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
48+ farRight = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
49+ nearLeft = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }
50+
51+ farLeftLat = visibleRegion.farLeft?.latitude ? : 0.0
52+ nearLeftLat = visibleRegion.nearLeft?.latitude ? : 0.0
53+ farLeftLng = visibleRegion.farLeft?.longitude ? : 0.0
54+ farRightLng = visibleRegion.farRight?.longitude ? : 0.0
55+ farLeftX = farLeft?.x ? : 0
56+ farLeftY = farLeft?.y ? : 0
57+ farRightX = farRight?.x ? : (farLeftX + 1 )
58+ nearLeftY = nearLeft?.y ? : (farLeftY + 1 )
59+ }
60+
61+ private fun isInvalid (): Boolean {
62+ return farLeftX == farRightX || farLeftY == nearLeftY || (farRightX == 1 && farLeftX == 0 ) || (nearLeftY == 1 && farLeftY == 0 )
63+ }
2664
27- override fun fromScreenLocation (obj : IObjectWrapper ? ): LatLng ? {
28- Log .d(TAG , " fromScreenLocation" )
29- return try {
30- obj.unwrap<Point >()?.let {
31- projection.fromScreenLocation(it).toGms()
65+ override fun fromScreenLocation (obj : IObjectWrapper ? ): LatLng ? = try {
66+ obj.unwrap<Point >()?.let {
67+ if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null ) {
68+ if (isInvalid()) {
69+ Log .w(TAG , " Invalid projection layout, fallback to SDK" )
70+ projection.fromScreenLocation(Point (it)).toGms()
71+ } else {
72+ val xPercent = (it.x.toFloat() - farLeftX) / (farRightX - farLeftX)
73+ val yPercent = (it.y.toFloat() - farLeftY) / (nearLeftY - farLeftY)
74+
75+ val lon = farLeftLng + xPercent * (farRightLng - farLeftLng)
76+ val lat = farLeftLat + yPercent * (nearLeftLat - farLeftLat)
77+
78+ Log .d(TAG , " fromScreenLocation: $it -> lat: $lat lon: $lon " )
79+
80+ LatLng (lat, lon)
81+ }
82+ } else {
83+ projection.fromScreenLocation(Point (it)).toGms()
3284 }
33- } catch (e: Exception ) {
34- Log .d(TAG , " fromScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs" )
35- LatLng (0.0 , 0.0 )
3685 }
86+ } catch (e: Exception ) {
87+ Log .d(TAG , " fromScreenLocation() error" , e)
88+ LatLng (0.0 , 0.0 )
3789 }
3890
39- override fun toScreenLocation (latLng : LatLng ? ): IObjectWrapper {
40- Log .d(TAG , " toScreenLocation: $latLng " )
41- return try {
42- ObjectWrapper .wrap(latLng?.toHms()?.let {
43- projection.toScreenLocation(it).let { Point (it.x, it.y) }
44- })
45- } catch (e: Exception ) {
46- Log .d(TAG , " toScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs" )
47- ObjectWrapper .wrap(Point (0 , 0 ))
48- }
91+ override fun toScreenLocation (latLng : LatLng ? ): IObjectWrapper = try {
92+ ObjectWrapper .wrap(latLng?.toHms()?.let {
93+ if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null ) {
94+ if (isInvalid()) {
95+ Log .w(TAG , " Invalid projection layout, fallback to SDK" )
96+ projection.toScreenLocation(it).let { p -> Point (p.x, p.y) }
97+ } else {
98+ val xPercent = (it.longitude - farLeftLng) / (farRightLng - farLeftLng)
99+ val yPercent = (it.latitude - farLeftLat) / (nearLeftLat - farLeftLat)
100+
101+ val x = farLeftX + xPercent * (farRightX - farLeftX)
102+ val y = farLeftY + yPercent * (nearLeftY - farLeftY)
103+
104+ Log .d(TAG , " toScreenLocation: $latLng -> x: $x y: $y " )
105+
106+ Point (x.roundToInt(), y.roundToInt())
107+ }
108+ } else {
109+ projection.toScreenLocation(it).let { p -> Point (p.x, p.y) }
110+ }
111+ })
112+ } catch (e: Exception ) {
113+ Log .d(TAG , " toScreenLocation() error" , e)
114+ ObjectWrapper .wrap(Point (0 , 0 ))
49115 }
50116
51117 override fun getVisibleRegion (): VisibleRegion ? {
52- val visibleRegion = projection.visibleRegion
53118 if (visibleRegion.farLeft.latitude.isNaN() || visibleRegion.farLeft.longitude.isNaN()) {
54119 return lastVisibleRegion
55120 }
0 commit comments