﻿B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=StaticCode
Version=11.2
@EndOfDesignText@
'B4A=True
'Group=Default Group
'ModulesStructureVersion=1
'Type=StaticCode
'Version=10.6
'@EndOfDesignText@

Sub Process_Globals
	'These global variables will be declared once when the application starts.
	'These variables can be accessed from all modules.
	Type TMapTileXY(fX As Long,fY As Long)
	Type TMapLatLng(fLat As Double,fLng As Double)
	Type TMapGPS(fLatLng As TMapLatLng,fBearing As Int)
	Type TMap(fCenterLatLng As TMapLatLng,fZoomLevel As Int,fCompassDirection As Double,fShowMenu As Boolean,fShowGrid As Boolean, _
			  fShowCenter As Boolean,fShowLandmark As Boolean,fShowCenterLatLng As Boolean,fShowZoom As Boolean,fShowScale As Boolean, _
			  fOfflineMode As Boolean,fShowCompass As Boolean,fShowShapes As Boolean,fShapes As Map,fShowGPS As Boolean,fFollowGPS As Boolean,fGPS As TMapGPS, _
			  bMultiShapeClick As Boolean)  'bMultiShapeClick added RBS 02/05/2022
	Type TMapBoxLatLng(fLeftTop As TMapLatLng,fRightBottom As TMapLatLng)
	Type TMapTileNumberOffset(fTile As Long,fOffset As Double)
	Type TMapPoint(fX As Double, fY As Double)
	Type TZoomColsRows(iCols As Int, iRows As Int)
	
	Public mapDBRowsColumns As Map 'added RBS 14/03/2022
	Public tMapCentre As TMapLatLng 'added RBS 13/02/2022
	
	'public constants
	Public Const cTileSize As Double = 256dip
	Public Const cMinLat As Double = -85.0511
	Public Const cMaxLat As Double = 85.0511
	Public Const cMinLng As Double = -180.0
	Public Const cMaxLng As Double = 180.0
	
	'will be set in Sub SetupMapDBRowsColumns
	'----------------------------------------
	Public iMinZoomLevel As Int
	Public iMaxZoomLevel As Int
	
	Public const dMapMinLat As Double = 52.536271
	Public const dMapMaxLat As Double = 52.69365
	Public const dMapMinLng As Double = -2.373052
	Public const dMapMaxLng As Double = -2.021473
	
	'RBS added 03/05/2022
	'these values will need to be set at initializing the map, values set by me at 1,2,3 and 4
	'this is only needed if multiShapeClick is set to False in the cvMap designer, or set to False
	'in multiShapeClick, otherwise these values won't be used
	'---------------------------------------------------------------------------------------------
	Public iCircleLayer As Int 
	Public iImageLayer As Int
	Public iPolygonLayer As Int
	Public iLineLayer As Int
	
End Sub

'return true if a point is in a rect else false
Public Sub PointInRect(aPoint As TMapPoint,aRect As B4XRect) As Boolean
	Return aPoint.fX>=aRect.Left And aPoint.fX<=aRect.Right And aPoint.fY>=aRect.Top And aPoint.fY<=aRect.Bottom
End Sub

'return distance between 2 points
public Sub distanceBetween2Points(aPoint1 As TMapPoint,aPoint2 As TMapPoint) As Double
	Return Sqrt(Power((aPoint1.fX-aPoint2.fX),2) + Power((aPoint1.fy-aPoint2.fy),2))
End Sub

'return a valid lat
public Sub validLat(aLat As Double) As Double
	Return Max(cMinLat,Min(aLat,cMaxLat))
End Sub

'return a valid lng
public Sub validLng(aLng As Double) As Double
	Return Max(cMinLng,Min(aLng,cMaxLng))
End Sub

'return a valid zoomLevel
public Sub validZoomLevel(aZoomLevel As Int) As Int
	Return Max(iMinZoomLevel,Min(aZoomLevel,iMaxZoomLevel))
End Sub

'return a valid compassDirection
public Sub validCompassDirection(aCompassDirection As Double) As Double
	#if b4i
		Dim d As Double=Bit.FMod(aCompassDirection, 360)
	#Else
	Dim d As Double=aCompassDirection Mod 360
	#End If
	If d<0 Then
		d=360+d
	End If
	Return Round(d)
End Sub

'return a TLatLng from lat/lng
public Sub initLatLng(aLat As Double,aLng As Double) As TMapLatLng
	Dim ll As TMapLatLng
	ll.Initialize
	ll.fLat=validLat(aLat)
	ll.fLng=validLng(aLng)
	Return ll
End Sub

'return a TBoxLatLng from Lat/Lng (left top) and Lat/Lng (Right Bottom)
Public Sub initBoxLatLng(aLatTop As Double, aLngLeft As Double, aLatBottom As Double, aLngRight As Double) As TMapBoxLatLng
	Dim b As TMapBoxLatLng
	b.Initialize
	b.fLeftTop = initLatLng(aLatTop, aLngLeft)
	b.fRightBottom = initLatLng(aLatBottom, aLngRight)
	Return b
End Sub

'return a TMapGPS from lat/lng and bearing
public Sub initGPS(aLatLng As TMapLatLng, aBearing As Int) As TMapGPS
	Dim g As TMapGPS
	g.Initialize
	g.fLatLng=aLatLng
	g.fBearing=aBearing
	Return g
End Sub

'return a tmap
public Sub initMap(aLatLng As TMapLatLng, _
				   aZoomLevel As Int, _
				   aCompassDirection As Double, _
				   aOfflineMode As Boolean, _
				   aShowMenu As Boolean, _
				   aShowGrid As Boolean, _
				   aShowCenter As Boolean, _
				   aShowLandmark As Boolean, _
				   aShowCenterLatLng As Boolean, _
				   aShowZoom As Boolean, _
				   aShowScale As Boolean, _
				   aShowCompass As Boolean, _
				   aShowShapes As Boolean, _
				   aShapes As Map, _
				   aShowGPS As Boolean, _
				   aFollowGPS As Boolean, _
				   aGPS As TMapGPS, _
				   bMultiShapeClick As Boolean) As TMap
				   
	Dim mi As TMap
	
	mi.fCenterLatLng=aLatLng
	mi.fCompassDirection=aCompassDirection
	mi.fOfflineMode=aOfflineMode
	mi.fShowCenter=aShowCenter
	mi.fShowCenterLatLng=aShowCenterLatLng
	mi.fShowCompass=aShowCompass
	mi.fShowGrid=aShowGrid
	mi.fShowLandmark=aShowLandmark
	mi.fShowShapes=aShowShapes
	mi.fShowMenu=aShowMenu
	mi.fShowScale=aShowScale
	mi.fShowZoom=aShowZoom
	mi.fZoomLevel=aZoomLevel
	mi.fShapes=aShapes
	mi.fShowGPS=aShowGPS
	mi.fFollowGPS=aFollowGPS
	mi.fGPS=aGPS
	mi.bMultiShapeClick = bMultiShapeClick 'added RBS 02/05/2022
	
	'added <<<<<<<
	tMapCentre.fLat = aGPS.fLatLng.fLat
	tMapCentre.fLng = aGPS.fLatLng.fLng
	
	Return mi
	
End Sub

'Return a TMapPoint from X And Y
public Sub initPoint(aX As Int,aY As Int) As TMapPoint
	Dim p As TMapPoint
	p.Initialize
	p.fX=aX
	p.fY=aY
	Return p
End Sub

'return a TTileXY from X and Y
public Sub initTileXY(aX As Long,aY As Long) As TMapTileXY
	Dim fTileXY As TMapTileXY
	fTileXY.Initialize
	fTileXY.fX=aX
	fTileXY.fY=aY
	Return fTileXY
End Sub

'return a clMapShapeCircle instance
public Sub instanceShapeCircle(acvMap As cvMap, aShape As TMapShapeCircle) As clsMapShapeCircle
	Dim s As clsMapShapeCircle
	s.Initialize(acvMap,aShape)
	Return s
End Sub

'return a clMapShapeLine instance
public Sub instanceShapeLine(acvMap As cvMap,aShape As TMapShapeLine) As clsMapShapeLine
	Dim s As clsMapShapeLine
	s.Initialize(acvMap,aShape)
	Return s
End Sub

'return a clMapShapePolygon instance
public Sub instanceShapePolygon(acvMap As cvMap,aShape As TMapShapePolygon) As clsMapShapePolygon
	Dim s As clsMapShapePolygon
	s.Initialize(acvMap,aShape)
	Return s
End Sub

'return a clMapShapeImage instance
public Sub instanceShapeImage(acvMap As cvMap,aShape As TMapShapeImage) As clsMapShapeImage
	Dim s As clsMapShapeImage
	s.Initialize(acvMap,aShape)
	Return s
End Sub

'return a TShapeCircle instance
public Sub initShapeCircle(aLatLng As TMapLatLng,aRadius As Double,aColor As Int,aFilled As Boolean,aStrokeWidth As Double,aData As Object) As TMapShapeCircle
	Dim s As TMapShapeCircle
	s.Initialize
	s.fLatLng=aLatLng
	s.fRadius=aRadius
	s.fColor=aColor
	s.fFilled=aFilled
	s.StrokeWidth=aStrokeWidth
	s.fData=aData
	Return s
End Sub

'return a TShapeLine instance
public Sub initShapeLine(aLatLng1 As TMapLatLng,aLatLng2 As TMapLatLng,aColor As Int,aStrokeWidth As Double,aData As Object) As TMapShapeLine
	Dim s As TMapShapeLine
	s.Initialize
	s.fLatLng1=aLatLng1
	s.fLatLng2=aLatLng2
	s.fColor=aColor
	s.fStrokeWidth=aStrokeWidth
	s.fData=aData
	Return s
End Sub

'return a TShapePolygon instance
public Sub initShapePolygon(aLatLng As List,aColor As Int,aFilled As Boolean,aStrokeWidth As Double,aData As Object) As TMapShapePolygon
	Dim s As TMapShapePolygon
	s.Initialize
	s.fLatLng=aLatLng
	s.fColor=aColor
	s.fFilled=aFilled
	s.fStrokeWidth=aStrokeWidth
	s.fData=aData
	Return s
End Sub

'return a TShapeImage instance
public Sub initShapeImage(aLatLng As TMapLatLng,aBitmap As B4XBitmap,aRotation As Double,aData As Object) As TMapShapeImage
	Dim s As TMapShapeImage
	s.Initialize
	s.fLatLng=aLatLng
	s.fBitmap=aBitmap
	s.fRotation=aRotation
	s.fData=aData
	Return s
End Sub

public Sub LngToTileX(aLng As Double,iZoom As Int) As Int
	Dim d As Double = (aLng + 180) / 360 * Power(2, iZoom)
	Return Floor(d)
End Sub

public  Sub LatToTileY(aLat As Double, iZoom As Int) As Int
	Dim d As Double = (1 - Logarithm(TanD(aLat) + 1 / CosD(aLat), cE) / cPI) / 2 * Power(2, iZoom)
	Return Floor(d)
End Sub

Public Sub GetCenterOfBB(BB As TMapBoxLatLng) As TMapLatLng
	Return initLatLng((BB.fRightBottom.fLat + BB.fLeftTop.flat) / 2, (BB.fLeftTop.fLng + BB.fRightBottom.fLng) / 2)
End Sub

Public Sub GetCenterOfTwoLatLon(tLL1 As TMapLatLng,tLL2 As TMapLatLng) As TMapLatLng
	Return initLatLng((tLL1.fLat + tLL2.flat) / 2, (tLL1.fLng + tLL2.fLng) / 2)
End Sub

Public Sub GetZoomToShowAll(tLL As TMapLatLng, BB As TMapBoxLatLng) As Int
	
	Dim i As Int
	Dim dLatDiff As Double
	Dim dLngDiff As Double
	Dim iMultiply As Int
	Dim dMinLat As Double = BB.fRightBottom.fLat
	Dim dMaxLat As Double = BB.fLeftTop.fLat
	Dim dMinLng As Double = BB.fLeftTop.fLng
	Dim dMaxLng As Double = BB.fRightBottom.fLng
	
	For i = iMaxZoomLevel To iMinZoomLevel Step - 1
		If i = iMaxZoomLevel Then
			iMultiply = 1
		Else
			iMultiply = Power(2, iMaxZoomLevel - i)
		End If
		
		dLatDiff = General.dFindZoomFactorLat * iMultiply '0.00046
		dLngDiff = General.dFindZoomFactorLng * iMultiply '0.00046
		
		If dMaxLat < tLL.fLat + dLatDiff Then
			If dMinLat > tLL.fLat  - dLatDiff Then
				If dMaxLng < tLL.fLng + dLngDiff Then
					If dMinLng > tLL.fLng - dLngDiff Then
						Return i
					End If
				End If
			End If
		End If
	Next
	
	Return iMinZoomLevel
	
End Sub

Sub SetupMapDBRowsColumns(RS1 As ResultSet)
	
	Dim c As Int
	
	mapDBRowsColumns.Initialize
	
	Do While RS1.NextRow
		Dim arrInt(4) As Int
		For c = 0 To 3
			arrInt(c) = RS1.GetInt2(c + 1)
		Next
		mapDBRowsColumns.Put(RS1.GetInt2(0), arrInt)
	Loop
	
	iMinZoomLevel = 100
	iMaxZoomLevel = 0
	
	'get the min and max zoom levels
	For Each iKey In mapDBRowsColumns.Keys
		If iKey > iMaxZoomLevel Then
			iMaxZoomLevel = iKey
		End If
		If iKey < iMinZoomLevel Then
			iMinZoomLevel = iKey
		End If
	Next
	
End Sub

'checks if a tile is in the DB, directly from a map
Public Sub TileInDB(iZoom As Int, iColumn As Int, iRow As Int) As Boolean
	
	Dim arrInt() As Int = mapDBRowsColumns.Get(iZoom)
	Return iColumn >= arrInt(0) And iColumn <= arrInt(1) And iRow >= arrInt(2) And iRow <= arrInt(3)
	
End Sub

'gets the number of tiles given the min- and max-coordinates and the zoomlevel range
Public Sub GetTotalTiles(BB As TMapBoxLatLng,  iMinZoom As Int, iMaxZoom As Int) As Long
						 
	Dim iMinX As Int
	Dim iMaxX As Int
	Dim iMinY As Int
	Dim iMaxY As Int
	Dim lTilesForZoom As Long
	Dim lTilesTotal As Long
	Dim dMinLat As Double = BB.fRightBottom.fLat
	Dim dMaxLat As Double = BB.fLeftTop.fLat
	Dim	dMinLng As Double = BB.fLeftTop.fLng
	Dim dMaxLng As Double = BB.fRightBottom.fLng
	
	For z = iMinZoom To iMaxZoom
		iMinX = LngToTileX(dMinLng, z)
		iMaxX = LngToTileX(dMaxLng, z)
		iMinY = LatToTileY(dMaxLat, z)
		iMaxY = LatToTileY(dMinLat, z)
		lTilesForZoom = (Abs(iMaxX - iMinX) + 1) * (Abs(iMaxY - iMinY) + 1)
		lTilesTotal = lTilesTotal + lTilesForZoom
	Next
	
	Return lTilesTotal
		
End Sub

'gets the center of a TMapBoxLatLng bounding box
Public Sub GetCenterFromBB(BB As TMapBoxLatLng) As TMapLatLng

	Dim tLL As TMapLatLng

	tLL.Initialize
	tLL.fLat = BB.fRightBottom.flat + (BB.fLeftTop.fLat - BB.fRightBottom.flat) / 2
	tLL.fLng = BB.fLeftTop.fLng + (BB.fRightBottom.fLng - BB.fLeftTop.fLng) / 2
	
	Return tLL
	
End Sub

Sub GetBBFromWholeMapArea() As TMapBoxLatLng
	
	Dim BB As TMapBoxLatLng = initBoxLatLng(dMapMaxLat, dMapMinLng, dMapMinLat, dMapMaxLng)
	Return BB
	
End Sub

Sub GetBBFromPolygon(tMSP As TMapShapePolygon) As TMapBoxLatLng
	
	Dim dMinLat As Double  = cMaxLat
	Dim dMaxLat As Double = cMinLat
	Dim dMinLng As Double = cMaxLng
	Dim dMaxLng As Double = cMinLng

	
	For Each tLL As TMapLatLng In tMSP.fLatLng
		If tLL.fLat < dMinLat Then
			dMinLat = tLL.fLat
		Else
			If tLL.fLat > dMaxLat Then
				dMaxLat = tLL.flat
			End If
		End If
		If tLL.fLng < dMinLng Then
			dMinLng = tLL.fLng
		Else
			If tLL.fLng > dMaxLng Then
				dMaxLng = tLL.fLng
			End If
		End If
	Next
	
	Dim BB As TMapBoxLatLng = initBoxLatLng(dMaxLat,dMinLng,dMinLat,dMaxLng)
	
	Return BB
	
End Sub