Skip to content

Instantly share code, notes, and snippets.

@Militoarg
Created June 11, 2021 01:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Militoarg/e33a843ed4caed3a60561edb69d75f3d to your computer and use it in GitHub Desktop.
Save Militoarg/e33a843ed4caed3a60561edb69d75f3d to your computer and use it in GitHub Desktop.
it looks to lat and lon coordinates to get maps without labels, just streets of zone around.
#!/usr/bin/python
# GoogleMapDownloader.py
# Created by Emilio Riquelme [emilioriquelme@gmail.com]
#
# A script which when given a longitude, latitude and zoom level downloads a
# high resolution google map
import urllib.request
from PIL import Image
import os
import math
from math import pi, log, tan, exp, atan, log2, floor
from pygeotile.tile import Tile
from pygeotile.point import Point
from PyQt5 import QtCore, QtWidgets, QtGui
import time
#C:\ProgramData\Anaconda3\Library\mingw-w64\bin
#C:\ProgramData\Anaconda3\Library\usr\bin
#C:\ProgramData\Anaconda3\Library\bin
class GoogleMapDownloader:
"""
A class which generates high resolution google maps images given
a longitude, latitude and zoom level
"""
def __init__(self, lat, lng, zoom=12):
"""
GoogleMapDownloader Constructor
Args:
lat: The latitude of the location required
lng: The longitude of the location required
zoom: The zoom level of the location required, ranges from 0 - 23
defaults to 12
"""
self._lat = float(lat)
self._lng = float(lng)
self._zoom = int(zoom)
my_path = os.path.abspath(os.path.dirname(__file__))
self.relpath = os.path.join(my_path, "../../")
#self.relpath='../../'
self.ZOOM0_SIZE = 256 # Not 512
self.proxy= {'https': 'https://177.92.20.182:46212',
'https': 'https://200.255.122.170:8080',
'https': 'https://80.187.140.26:8080'
}
#self.proxy=['socks5://Username:Password@IP1:20000',
# 'socks5://Username:Password@IP2:20000',
# 'socks5://Username:Password@IP3:20000',
# 'socks5://Username:Password@IP4:20000']
self.kml = '''<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Clean Map:lat{}_lng{}</name>
<open>1</open>
<description>Google maps with no labels</description>
<Folder>
<name>Ground Overlays</name>
<visibility>1</visibility>
<description>Examples of ground overlays</description>
<GroundOverlay>
<name>Large-scale overlay on terrain</name>
<visibility>1</visibility>
<description>Overlay shows Mount Etna erupting on July 13th, 2001.</description>
<LookAt>
<longitude>{}</longitude>
<latitude>{}</latitude>
<altitude>0</altitude>
<heading>0</heading>
<tilt>0</tilt>
<range>1000</range>
</LookAt>
<Icon>
<href>{}</href>
</Icon>
<LatLonBox>
<north>{}</north>
<south>{}</south>
<east>{}</east>
<west>{}</west>
<rotation>0</rotation>
</LatLonBox>
</GroundOverlay>
</Folder>
</Document>
</kml>
'''
def getXY(self):
"""
Generates an X,Y tile coordinate based on the latitude, longitude
and zoom level
Returns: An X,Y tile coordinate
"""
tile_size = 256
# Use a left shift to get the power of 2
# i.e. a zoom level of 2 will have 2^2 = 4 tiles
numTiles = 1 << self._zoom
# Find the x_point given the longitude
point_x = (tile_size / 2 + self._lng * tile_size / 360.0) * numTiles // tile_size
# Convert the latitude to radians and take the sine
sin_y = math.sin(self._lat * (math.pi / 180.0))
# Calulate the y coorindate
point_y = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
tile_size / (2 * math.pi))) * numTiles // tile_size
return int(point_x), int(point_y)
#obtiene lat y long a partir de punto x e y de la imagen
def getTileBounds(self,point_x,point_y,zoom):
# Use a left shift to get the power of 2
# i.e. a zoom level of 2 will have 2^2 = 4 tiles
# get latitud longitud coordinates from tile bound
out = Tile.from_tms(point_x,point_y,zoom)
#separa en ambos puntos por latitud y longitud
return out.bounds
# Geo-coordinate in degrees => Pixel coordinate
def g2p(self,lat, lon, zoom):
return (
# x
self.ZOOM0_SIZE * (2 ** zoom) * (1 + lon / 180) / 2,
# y
self.ZOOM0_SIZE / (2 * pi) * (2 ** zoom) * (pi - log(tan(pi / 4 * (1 + lat / 90))))
)
# Pixel coordinate => geo-coordinate in degrees
def p2g(self,x, y, zoom):
return (
# lat
(atan(exp(pi - y / self.ZOOM0_SIZE * (2 * pi) / (2 ** zoom))) / pi * 4 - 1) * 90,
# lon
(x / self.ZOOM0_SIZE * 2 / (2 ** zoom) - 1) * 180,
)
#crea kml archivo con coordenadas
def kmlPlaceMap(self,coords,filepath):
file='{}KML_map_lat{}_lng{}.kml'.format(self.relpath,self._lat,self._lng)
north,south,east,west = coords
with open(file,'w') as t:
t.write(self.kml.format(self._lat,self._lng,self._lng,self._lat,filepath,-north,-south,east,west))
#genera imagen
def generateImage(self,mapPath,tileSize, **kwargs):
"""
Generates an image by stitching a number of google map tiles together.
Args:
start_x: The top-left x-tile coordinate
start_y: The top-left y-tile coordinate
tile_width: The number of tiles wide the image should be -
defaults to 5
tile_height: The number of tiles high the image should be -
defaults to 5
Returns:
A high-resolution Goole Map image.
"""
start_x = kwargs.get('start_x', None)
start_y = kwargs.get('start_y', None)
tile_width = kwargs.get('tile_width', tileSize)
tile_height = kwargs.get('tile_height', tileSize)
# Check that we have x and y tile coordinates
if start_x == None or start_y == None:
start_x, start_y = self.getXY()
# Determine the size of the image
width, height = 256 * tile_width, 256 * tile_height
# Create a new image of the size require
map_img = Image.new('RGB', (width, height))
print(start_x,start_y,tile_width,tile_height,'x,y,wx,hy')
#print(self.g2p(self._lat,self._lng,self._zoom),'<-g2p')
#(x0,y0)=self.g2p(self._lat,self._lng,self._zoom)
coord = []
for x in range(0, tile_width):
for y in range(0, tile_height):
xPos = start_x+x+1-(tile_width//2)
yPos = start_y+y+1-(tile_height//2)
url = 'https://mt0.google.com/vt?x=' + str(xPos) + '&y=' + str(yPos) + '&z=' + str(self._zoom)+'&apistyle=s.t%3A0%7Cs.e%3Al%7Cp.v%3Aoff'
#url = 'https://mt0.google.com/vt?lyrs=m&x=' + str(xPos) + '&y=' + str(yPos) + '&z=' + str(self._zoom)+'&apistyle=s.t%3A0%7Cs.e%3Al%7Cp.v%3Aoff'
current_tile = str(x) + '-' + str(y)
urllib.request.urlretrieve(url, current_tile)
#im = Image.open(r'D:\WIP\LEAN\001.png')
im = Image.open(current_tile)
map_img.paste(im, (x * 256, y * 256))
coord.append(self.getTileBounds(xPos,yPos,17))
#print(current_tile,x*256,y*256,start_x+x,start_y+y,'<-x,y tile')
os.remove(current_tile)
start_lat = [(x[0][0]) for x in coord]
start_lng = [(x[0][1]) for x in coord]
end_lat = [(x[1][0]) for x in coord]
end_lng = [(x[1][1]) for x in coord]
lat= start_lat+end_lat
lng= start_lng+end_lng
#lat Long box
#print(max(lat),'<-sur|', min(lat),'<-norte',max(lng),'<-este',min(lng),'<-oeste')
latLngBox = (min(lat),max(lat),max(lng),min(lng))
#https://i.ibb.co/ZR9x7Yh/high-resolution-image01.png
self.kmlPlaceMap(latLngBox,mapPath)
return map_img
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super(MyWidget,self).__init__()
my_path = os.path.abspath(os.path.dirname(__file__))
self.relpath = os.path.join(my_path, "../../")
self.titleLabel = QtWidgets.QLabel('<font color=black>Answer these questions:</font>')
self.latLabel = QtWidgets.QLabel('<font color=red>What is the Latitude?</font>')
self.latLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.latInput = QtWidgets.QLineEdit()
self.latInput.setFixedWidth(150)
self.latInput.setPlaceholderText('33.9956661333')
self.lngLabel = QtWidgets.QLabel('<font color=blue>What is the Longitude?</font>')
self.lngLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.lngInput = QtWidgets.QLineEdit()
self.lngInput.setFixedWidth(150)
self.lngInput.setPlaceholderText('-120.5666661333')
self.zoomLabel = QtWidgets.QLabel('<font color=green>What is the map size?</font>')
self.zoomLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.zoomInput = QtWidgets.QSpinBox()
self.zoomInput.setValue(8)
self.zoomInput.setMinimum(2)
self.zoomInput.setMaximum(16)
self.zoomInput.setFixedWidth(50)
self.tilesizeLabel = QtWidgets.QLabel('(2048x2048 pixels)')
self.zoomLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.spinLayout = QtWidgets.QHBoxLayout()
self.spinLayout.addWidget(self.zoomInput)
self.spinLayout.addWidget(self.tilesizeLabel)
self.mapButton = QtWidgets.QPushButton('Generate clean map')
self.mapButton.setFixedWidth(150)
self.outLabel = QtWidgets.QLabel('<font color=black>Creating clean map...</font>')
self.outLabel.setAlignment(QtCore.Qt.AlignRight)
self.outLabel.hide()
#conexion
self.mapButton.clicked.connect(self.generateMap)
self.mapButton.clicked.connect(self.outLabel.show)
self.zoomInput.valueChanged.connect(self.showTile)
#layouts
self.parentLayout = QtWidgets.QGridLayout()
self.parentLayout.addWidget(self.titleLabel,0,1)
self.parentLayout.addWidget(self.latLabel,1,0)
self.parentLayout.addWidget(self.latInput,1,1)
self.parentLayout.addWidget(self.lngLabel,2,0)
self.parentLayout.addWidget(self.lngInput,2,1)
self.parentLayout.addWidget(self.zoomLabel,3,0)
#self.parentLayout.addWidget(self.zoomInput,3,1)
self.parentLayout.addLayout(self.spinLayout,3,1)
self.parentLayout.addWidget(self.mapButton,4,1)
self.parentLayout.addWidget(self.outLabel,4,0)
self.setLayout(self.parentLayout)
self.setWindowTitle('CleanMap Generator 1.5.7')
self.setMinimumWidth(320)
#muestra tilesize
def showTile(self):
val=256*self.zoomInput.value()
self.tilesizeLabel.setText('({}x{} pixels)'.format(val,val))
#genera el mapa
def generateMap(self):
self.outLabel.setText('Creating clean map...')
Latitude = self.latInput.text()
Longitude = self.lngInput.text()
zoom= 17
if len(Latitude) ==0 or len(Longitude)==0:
self.outLabel.setText('No inputs!')
return
print(Latitude,Longitude,zoom,'<- latlongzoom')
gmd = GoogleMapDownloader(Latitude,Longitude,zoom)
#33.9827179,-118.2411244,927
#print("The tile coorindates are {}".format(gmd.getXY()))
#0,5131578947368421
# Get the high resolution image
#img = gmd.generateImage()
#print(lat,lon,'<-lat y long puntual')
filePath="{}high_resolution_image_lat{}_lng{}.png".format(self.relpath,Latitude,Longitude)
try:
# Get the high resolution image
self.outLabel.setText('Creating clean map...')
time.sleep(0.1)
img = gmd.generateImage(filePath,self.zoomInput.value())
print(Latitude,Longitude,'<-lat y long puntual')
except IOError:
print("Could not generate the image - try adjusting the zoom level and checking your coordinates")
self.outLabel.setText('Could not generate the image')
else:
# Save the image to disk
img.save("{}high_resolution_image_lat{}_lng{}.png".format(self.relpath,Latitude,Longitude))
print("The map has successfully been created")
self.outLabel.setText('The map has successfully been created!')
def main():
# Create a new instance of GoogleMap Downloader
#gmd = GoogleMapDownloader(51.5171, 0.1062, 13)
#lat=33.9827179
#lon=-118.2411244
lat=33.982348699999996
lon=-118.24081859999998
app = QtWidgets.QApplication([])
form = MyWidget()
form.show()
app.exec_()
#sys.exit(app.exec_())
if __name__ == '__main__': main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment