# needs satellite img with equal padding in opposite directions # will use google map static api, 8k character limit of request URL # *how map is generated is, given the img size, it tries to find the right zoom to fit the points inside the size with greater than 0 padding # *one scale is for 640x640 size, 10m=1px at zoom=14; 1.1m=1px at zoom=17 # will have 10% padding in the img each side; by setting size accordingly # will call api with these parameters - key, size, maptype, format, path from PIL import Image # from haversine import haversine, Unit from geopy.distance import geodesic import requests import base64 import shutil import math # lat = 23.108696466469407 def mPerPxByZoom(zoom, lat): return 156543.03392 * math.cos(lat * math.pi / 180) / math.pow(2, zoom) def getDistBwPoints(p1, p2): # hsDist = haversine(p1, p2, unit=Unit.METERS) gpDist = geodesic(p1, p2).m return gpDist def getZoomLevel(len, lat, zoom=14): len640 = mPerPxByZoom(zoom, lat)*640 print("len", len) if len640 > len: while len640 > len: zoom += 1 len640 = mPerPxByZoom(zoom, lat)*640 # print(zoom, len640) return zoom-1, len640*2/640 else: while len640 < len: zoom -= 1 len640 = mPerPxByZoom(zoom, lat)*640 # print(zoom, len640) return zoom, len640/640 def getFieldMapImg(points, fieldMainLats, outPath="fieldMap.jpg"): # returns tuple of widthPx, heightPx, widthPad, heightPad maxLat = fieldMainLats['maxLat'] minLat = fieldMainLats['minLat'] maxLng = fieldMainLats['maxLng'] minLng = fieldMainLats['minLng'] centerLat = fieldMainLats['centerLat'] centerLng = fieldMainLats['centerLng'] #w-h in meters width2 = getDistBwPoints((centerLat, minLng), (centerLat, maxLng)) height2 = getDistBwPoints((maxLat, centerLng), (minLat, centerLng)) print(width2, height2) # return # get final img size, zoom, padding % # will have padding = 10%, minPad 15m each side; aspect ratio range = 0.5 or 2 width = width2 height = height2 aspectRatio = width/height print("aspect: ", aspectRatio) if aspectRatio < 0.5: width = 0.5*height elif aspectRatio > 2: height = 0.5*width print("new w-h: ", width, height) # calculate seperate padding for width, height minPadDis = 15 # in m widthPadPrcnt = 0.1 # one side if width == width2: minWidthPad10 = width*widthPadPrcnt if minWidthPad10 < minPadDis: widthPadPrcnt = minPadDis/width else: extraPad = (width-width2)/2 if extraPad < minPadDis: widthPadPrcnt = (minPadDis-extraPad)/width heightPadPrcnt = 0.1 if height == height2: minHeightPad10 = height*heightPadPrcnt if minHeightPad10 < minPadDis: heightPadPrcnt = minPadDis/height else: extraPad = (height-height2)/2 if extraPad < minPadDis: heightPadPrcnt = (minPadDis-extraPad)/height # isHeightBigger = height>width # minPadBy10 = (width2 if isHeightBigger else height2)*padPrcnt # if minPadBy10<15: # padPrcnt = 15/(width2 if isHeightBigger else height2) # calculate zoom level; need to check at which zoom 640px don't accomodate biggerLen and use one less zoom pWidth = width*(1+2*widthPadPrcnt) # with padding pHeight = height*(1+2*heightPadPrcnt) biggerLen = max(pWidth, pHeight) zoom, mPerPx = getZoomLevel(biggerLen, maxLat) finalWidth = pWidth/mPerPx # the pixel values finalHeight = pHeight/mPerPx print(finalWidth, finalHeight, zoom, mPerPx, widthPadPrcnt, heightPadPrcnt) # return # isMoreThan640 = biggerLen > 640 # # preferrable size is 640x640; rough cal- with padding = 480x516; (now we need to make larger one under 640 by dividing by 2) # # for >640 values, do divide by 640, log base2 and take ceil; then divide main values by 2 power that value # # for <640 values, do divide 640 by the number, log base2 and take floor, then multiply the number by 2 power that value # factor = math.pow(2, math.ceil(math.log(biggerLen/640, 2)) if isMoreThan640 else math.floor(math.log(640/biggerLen, 2))) # finalWidth = (width/factor if isMoreThan640 else width*factor)/10*1.2 # finalHeight = (height/factor if isMoreThan640 else height*factor)/10*1.2 # print(finalWidth, finalHeight, factor) path = "weight:0|" pointsKeys = list(points.keys()) pointsKeys.sort() for pointKey in pointsKeys: pointInfo = points[pointKey] path += "%s,%s|" % (pointInfo["Latitude"], pointInfo["Longitude"]) pointInfo = points[pointsKeys[0]] path += "%s,%s" % (pointInfo["Latitude"], pointInfo["Longitude"]) # print("path: ", path) api_key = "AIzaSyBO5HDklsIeFNmKMGDLoImadHH57eQ4c2k" api_key = "AIzaSyDnM_35WfYwhJmTSPxyyiMIcYte65mPitc" params = { "key": api_key, "format": "jpg", "maptype": "satellite", "path": path, "zoom": zoom, "size": "%sx%s" % (round(finalWidth), round(finalHeight)) } result = requests.get( "https://maps.googleapis.com/maps/api/staticmap", params=params, stream=True) if result.status_code == 200: with open(outPath, 'wb') as f: result.raw.decode_content = True shutil.copyfileobj(result.raw, f) return (finalWidth, finalHeight, ((pWidth-width2)/2)/width2, ((pHeight-height2)/2)/height2) else: return None def checkDownloadProcess(): read_file = open('papa.jpeg', 'rb') data = read_file.read() b64 = base64.b64encode(data) print(b64[:100]+b64[-100:]) # Save file decode_b64 = base64.b64decode(b64) out_file = open('papa_again.jpeg', 'wb') out_file.write(decode_b64) # checkDownloadProcess() # points = { # "a": {"Latitude": 23.108696466469407, "Longitude": 76.94931373000145}, # "P_1": {"Latitude": 23.108788361955472, "Longitude": 76.94893788546324}, # "P_2": {"Latitude": 23.107457721514155, "Longitude": 76.94890134036541}, # "P_3": {"Latitude": 23.10740036336785, "Longitude": 76.94929964840412}, # "P_4": {"Latitude": 23.108686598494, "Longitude": 76.94933719933033}, # } # maxLat = 23.108788361955472 # minLat = 23.10740036336785 # maxLng = 76.94933719933033 # minLng = 76.94890134036541 # fieldMainLats = { # 'maxLng': maxLng, # 'minLat': minLat, # 'minLng': minLng, # 'maxLat': maxLat, # 'centerLat': maxLat, # 'centerLng': maxLng, # } # getFieldMapImg(points, fieldMainLats) # for i in range(10): # mPerPx = mPerPxByZoom(i+10, lat) # print(i+10, mPerPx, mPerPx*200)