googleTile = {'tx': 68, 'ty': 42} tileBounds = { 'minx': 1252344.271424327, 'miny': 6574807.42497772, 'maxx': 1565430.3392804079, 'maxy': 6887893.492833804 } quadKey = "1202120" result = gm.LatLonToMeters(geographic['lat'], geographic['lon']) print(result) result = gm.MetersToLatLon(meters['mx'], meters['my']) print(result) result = gm.MetersToPixels(meters['mx'], meters['my'], zoom) print(result) result = gm.PixelsToTile(pixels['px'], pixels['py']) print(result) result = gm.PixelsToMeters(pixels['px'], pixels['py'], zoom) print(result) result = gm.TileBounds(tile['tx'], tile['ty'], zoom) print(result) result = gm.LatLonToTile(geographic['lat'], geographic['lon'], zoom) print(result) result = gm.MetersToTile(meters['mx'], meters['my'], zoom)
def pdfer(data, page_size=PAGE_SIZES['letter'], output='pdf'): shape_overlays = data.get('shape_overlays') point_overlays = data.get('point_overlays') grid = {'zoom': data.get('zoom')} center_lon, center_lat = data['center'] center_tile_x, center_tile_y = tileXY(float(center_lat), float(center_lon), int(data['zoom'])) dim_across, dim_up = data['dimensions'] if dim_across > dim_up: page_height, page_width, tiles_up, tiles_across = page_size else: page_width, page_height, tiles_across, tiles_up = page_size min_tile_x = center_tile_x - (tiles_across / 2) min_tile_y = center_tile_y - (tiles_up / 2) max_tile_x = min_tile_x + tiles_across max_tile_y = min_tile_y + tiles_up # Get base layer tiles base_pattern = 'http://d.tile.stamen.com/toner/{z}/{x}/{y}.png' if data.get('base_tiles'): base_pattern = data['base_tiles'] base_links = generateLinks(base_pattern, grid['zoom'], min_tile_x, min_tile_y, max_tile_x, max_tile_y) base_names = dl_write_all(base_links, 'base') # Get overlay tiles overlay_pattern = None if data.get('overlay_tiles'): overlay_pattern = data['overlay_tiles'] overlay_links = generateLinks(overlay_pattern, grid['zoom'], min_tile_x, min_tile_y, max_tile_x, max_tile_y) overlay_names = dl_write_all(overlay_links, 'overlay') now = datetime.now() date_string = datetime.strftime(now, '%Y-%m-%d_%H-%M-%S') outp_name = os.path.join('/tmp', '{0}.png'.format(date_string)) base_image_names = ['-'.join(l.split('/')[-3:]) for l in base_names] base_image_names = sorted([i.split('-')[-3:] for i in base_image_names], key=itemgetter(1)) for parts in base_image_names: z, x, y = parts y = y.rstrip('.png').rstrip('.jpg') z = z.rsplit('_', 1)[1] key = '-'.join([z, x, y]) grid[key] = {'bbox': tileEdges(float(x), float(y), int(z))} keys = sorted(grid.keys()) mercator = GlobalMercator() bb_poly = None bmin_rx = None bmin_ry = None if shape_overlays or point_overlays: polys = [] for k, v in grid.items(): try: one, two, three, four = grid[k]['bbox'] polys.append(box(two, one, four, three)) except TypeError: pass mpoly = MultiPolygon(polys) bb_poly = box(*mpoly.bounds) min_key = keys[0] max_key = keys[-2] bminx, bminy = grid[min_key]['bbox'][0], grid[min_key]['bbox'][1] bmaxx, bmaxy = grid[max_key]['bbox'][2], grid[max_key]['bbox'][3] bmin_mx, bmin_my = mercator.LatLonToMeters(bminx, bminy) bmax_mx, bmax_my = mercator.LatLonToMeters(bmaxx, bmaxy) bmin_px, bmin_py = mercator.MetersToPixels(bmin_mx, bmin_my, float(grid['zoom'])) bmax_px, bmax_py = mercator.MetersToPixels(bmax_mx, bmax_my, float(grid['zoom'])) bmin_rx, bmin_ry = mercator.PixelsToRaster(bmin_px, bmin_py, int(grid['zoom'])) if shape_overlays: all_polys = [] for shape_overlay in shape_overlays: shape_overlay = json.loads(shape_overlay) if shape_overlay.get('geometry'): shape_overlay = shape_overlay['geometry'] coords = shape_overlay['coordinates'][0] all_polys.append(Polygon(coords)) mpoly = MultiPolygon(all_polys) one, two, three, four, five = list( box(*mpoly.bounds).exterior.coords) left, right = LineString([one, two]), LineString([three, four]) top, bottom = LineString([two, three]), LineString([four, five]) left_to_right = left.distance(right) top_to_bottom = top.distance(bottom) if left_to_right > top_to_bottom: page_height, page_width, _, _ = page_size else: page_width, page_height, _, _ = page_size center_lon, center_lat = list(mpoly.centroid.coords)[0] if point_overlays: all_points = [] for point_overlay in point_overlays: point_overlay = json.loads(point_overlay) for p in point_overlay['points']: if p[0] and p[1]: all_points.append(p) mpoint = MultiPoint(all_points) center_lon, center_lat = list(mpoint.centroid.coords)[0] one, two, three, four, five = list( box(*mpoint.bounds).exterior.coords) left, right = LineString([one, two]), LineString([three, four]) top, bottom = LineString([two, three]), LineString([four, five]) left_to_right = left.distance(right) top_to_bottom = top.distance(bottom) if left_to_right > top_to_bottom: page_height, page_width, _, _ = page_size else: page_width, page_height, _, _ = page_size center_lon, center_lat = list(mpoint.centroid.coords)[0] print(center_lon, center_lat) arrays = [] for k, g in groupby(base_image_names, key=itemgetter(1)): images = list(g) fnames = ['/tmp/%s' % ('-'.join(f)) for f in images] array = [] for img in fnames: i = cv2.imread(img, -1) if isinstance(i, type(None)): i = np.zeros((256, 256, 4), np.uint8) elif i.shape[2] != 4: i = cv2.cvtColor(cv2.imread(img), cv2.COLOR_BGR2BGRA) array.append(i) arrays.append(np.vstack(array)) outp = np.hstack(arrays) cv2.imwrite(outp_name, outp) if overlay_pattern: overlay_outp_name = os.path.join('/tmp', 'overlay_{0}.png'.format(date_string)) overlay_image_names = [ '-'.join(l.split('/')[-3:]) for l in overlay_names ] overlay_image_names = sorted( [i.split('-')[-3:] for i in overlay_image_names], key=itemgetter(1)) arrays = [] for k, g in groupby(overlay_image_names, key=itemgetter(1)): images = list(g) fnames = ['/tmp/%s' % ('-'.join(f)) for f in images] array = [] for img in fnames: i = cv2.imread(img, -1) if isinstance(i, type(None)): i = np.zeros((256, 256, 4), np.uint8) elif i.shape[2] != 4: i = cv2.cvtColor(cv2.imread(img), cv2.COLOR_BGR2BGRA) array.append(i) arrays.append(np.vstack(array)) nuked = [os.remove(f) for f in fnames] outp = np.hstack(arrays) cv2.imwrite(overlay_outp_name, outp) base = cv2.imread(outp_name, -1) overlay = cv2.imread(overlay_outp_name, -1) overlay_g = cv2.cvtColor(overlay, cv2.COLOR_BGR2GRAY) ret, mask = cv2.threshold(overlay_g, 10, 255, cv2.THRESH_BINARY) inverted = cv2.bitwise_not(mask) overlay = cv2.bitwise_not(overlay, overlay, mask=inverted) base_alpha = 0.55 overlay_alpha = 1 for channel in range(3): x, y, d = overlay.shape base[:,:,channel] = (base[:,:,channel] * base_alpha + \ overlay[:,:,channel] * overlay_alpha * \ (1 - base_alpha)) / \ (base_alpha + overlay_alpha * (1 - base_alpha)) cv2.imwrite(outp_name, base) ########################################################################### # Code below here is for drawing vector layers within the PDF # # Leaving it in just because it was a pain to come up with the first time # ########################################################################### if shape_overlays or point_overlays: im = cairo.ImageSurface.create_from_png(outp_name) ctx = cairo.Context(im) if shape_overlays: for shape_overlay in shape_overlays: shape_overlay = json.loads(shape_overlay) if shape_overlay.get('geometry'): shape_overlay = shape_overlay['geometry'] color = hex_to_rgb('#f06eaa') coords = shape_overlay['coordinates'][0] x, y = get_pixel_coords(coords[0], grid['zoom'], bmin_rx, bmin_ry) ctx.move_to(x, y) ctx.set_line_width(4.0) red, green, blue = [float(c) for c in color] ctx.set_source_rgba(red / 255, green / 255, blue / 255, 0.3) for p in coords[1:]: x, y = get_pixel_coords(p, grid['zoom'], bmin_rx, bmin_ry) ctx.line_to(x, y) ctx.close_path() ctx.fill() ctx.set_source_rgba(red / 255, green / 255, blue / 255, 0.5) for p in coords[1:]: x, y = get_pixel_coords(p, grid['zoom'], bmin_rx, bmin_ry) ctx.line_to(x, y) ctx.close_path() ctx.stroke() ctx.set_line_width(2.0) if point_overlays: for point_overlay in point_overlays: point_overlay = json.loads(point_overlay) color = hex_to_rgb(point_overlay['color']) for p in point_overlay['points']: if p[0] and p[1]: pt = Point((float(p[0]), float(p[1]))) if bb_poly.contains(pt): nx, ny = get_pixel_coords(p, grid['zoom'], bmin_rx, bmin_ry) red, green, blue = [float(c) for c in color] ctx.set_source_rgba(red / 255, green / 255, blue / 255, 0.6) ctx.arc( nx, ny, 5.0, 0, 50) # args: center-x, center-y, radius, ?, ? ctx.fill() ctx.arc(nx, ny, 5.0, 0, 50) ctx.stroke() im.write_to_png(outp_name) scale = 1 # Crop image from center center_point_x, center_point_y = latlon2xy(float(center_lat), float(center_lon), float(data['zoom'])) offset_x = (center_point_x - float(center_tile_x)) + 50 offset_y = (center_point_y - float(center_tile_y)) - 50 outp_image = cv2.imread(outp_name, -1) pixels_up, pixels_across, channels = outp_image.shape center_x, center_y = (pixels_across / 2) + offset_x, (pixels_up / 2) + offset_y start_y, end_y = center_y - (page_height / 2), center_y + (page_height / 2) start_x, end_x = center_x - (page_width / 2), center_x + (page_width / 2) cv2.imwrite(outp_name, outp_image[start_y:end_y, start_x:end_x]) if output == 'pdf': outp_file_name = outp_name.rstrip('.png') + '.pdf' pdf = cairo.PDFSurface(outp_file_name, page_width, page_height) ctx = cairo.Context(pdf) image = cairo.ImageSurface.create_from_png(outp_name) ctx.set_source_surface(image) ctx.paint() pdf.finish() elif output == 'jpeg': outp_file_name = outp_name.rstrip('.png') + '.jpg' jpeg = cv2.cvtColor(cv2.imread(outp_name, -1), cv2.COLOR_RGBA2RGB) cv2.imwrite(outp_file_name, jpeg) return outp_file_name
class TileGrid(object): #def __init__(self, parentgeometry, bearing = 0.0, zoomlevel = 16, lat = dec.Decimal('32.829608'), lon = dec.Decimal('35.080498')): #def __init__(self, parentgeometry, bearing = 0.0, zoomlevel = 16, lat = dec.Decimal('32.330347'), lon = dec.Decimal('34.851395')): def __init__(self, bearing=0.0, zoomlevel=16, lat=decimal.Decimal('32.018300'), lon=decimal.Decimal('34.898161'), parent=None): #set initial values self.parent = parent self.bearingSensitivity = decimal.Decimal('0.00001') self.bearing = bearing self.zoomlevel = zoomlevel self.lat = lat self.lon = lon self.gx, self.gy = None, None self.velocity = 0.0 self.sysPath = os.path.join(sys.path[0], "") self.mapPath = self.sysPath self.maxZoomLevel = 16 self.destlat = decimal.Decimal('32.776250') self.destlon = decimal.Decimal('35.028946') self.distance = 0 self.setBounds(parent.geometry().width(), parent.geometry().height()) self.halfboundx = math.ceil(self.boundx / 2) self.halfboundy = math.ceil(self.boundy / 2) #make GlobalMercator instance self.mercator = GlobalMercator() # create pathways self.refresh() def setMapPath(self, path): if path != "": self.mapPath = path + "/" print self.mapPath def setBounds(self, newx, newy): self.boundx, self.boundy = newx, newy # adding 16px to halfbounds height and width to display icons self.halfboundx = int(math.ceil(self.boundx / 2)) + 31 self.halfboundy = int(math.ceil(self.boundy / 2)) + 31 def getOffset(self): 'get pixel offset of coordinates from 0,0 of tile' offpx = self.px - self.tx * self.mercator.tileSize #the y pixel coordinate system begins from top offpy = self.mercator.tileSize - (self.py - self.ty * self.mercator.tileSize) return offpx, offpy def moveTo(self, lat, lon, calculateBearing=True): 'move position to lat, lon and update all properties' #update bearing from previous position if calculateBearing: if abs(lon - self.lon) > self.bearingSensitivity \ or abs(lat - self.lat) > self.bearingSensitivity: self.bearing = math.degrees( math.atan2(lon - self.lon, lat - self.lat)) if self.bearing < 0: self.bearing += 360 self.lat = lat self.lon = lon #get meters from lat/lon mx, my = self.mercator.LatLonToMeters(float(self.lat), float(self.lon)) #dx, dy = self.mercator.LatLonToMeters( float(self.destlat), float(self.destlon) ) #self.distance = math.sqrt(math.pow(mx-dx, 2) + math.pow(my-dy, 2 )) #get pixels from meters self.px, self.py = self.mercator.MetersToPixels(mx, my, self.zoomlevel) #get tile from pixels self.tx, self.ty = self.mercator.PixelsToTile(int(self.px), int(self.py)) #get google tile self.gx, self.gy = self.mercator.GoogleTile(self.tx, self.ty, self.zoomlevel) #update offset of tile self.offpx, self.offpy = self.getOffset() #TODO: calculate loadRect bounds for peripherial tiles self.sizex = int(math.ceil(self.boundx / self.mercator.tileSize)) + 1 self.sizey = int(math.ceil(self.boundy / self.mercator.tileSize)) + 1 halfdeltax = int(math.ceil(self.sizex / 2)) + 1 halfdeltay = int(math.ceil(self.sizey / 2)) + 1 self.images = set() offtilex = halfdeltax * self.mercator.tileSize + self.offpx for x in range(self.gx - halfdeltax, self.gx + halfdeltax + 1): offtiley = halfdeltay * self.mercator.tileSize + self.offpy for y in range(self.gy - halfdeltay, self.gy + halfdeltay + 1): fname = "%i/gm_%i_%i_%i.png" % (self.zoomlevel, x, y, self.zoomlevel) if not QtCore.QFile.exists(self.mapPath + fname): fname = "404.png" self.images.add((QtCore.QPointF(-offtilex, -offtiley), fname)) offtiley -= self.mercator.tileSize offtilex -= self.mercator.tileSize # print fname self.bounds = { 'TL': (self.px - self.halfboundx, self.py - self.halfboundy), 'TR': (self.px + self.halfboundx, self.py - self.halfboundy), 'BR': (self.px + self.halfboundx, self.py + self.halfboundy), 'BL': (self.px - self.halfboundx, self.py + self.halfboundy) } self.pathways = QtGui.QPolygonF() # create waypoints icons self.visible_waypoints = set() for wp in self.waypoints_pixels: x = wp[0] - self.px y = self.py - wp[1] self.pathways.append(QtCore.QPointF(x, y)) if self.isVisible(wp): self.visible_waypoints.add(QtCore.QPointF(x - 15, y - 32)) # print self.waypoints_pixels def isVisible(self, wp): return wp[0] > self.bounds['TL'][0] and \ wp[0] < self.bounds['TR'][0] and \ wp[1] > self.bounds['TL'][1] and \ wp[1] < self.bounds['BL'][1] def refresh(self): self.waypoints_pixels = set() for wp in self.parent.waypoint: wpm = self.mercator.LatLonToMeters(wp[0], wp[1]) wppx = self.mercator.MetersToPixels(wpm[0], wpm[1], self.zoomlevel) self.waypoints_pixels.add(wppx) self.moveTo(self.lat, self.lon) def setZoom(self, zoom): self.zoomlevel = zoom self.refresh() def zoomIn(self): if self.zoomlevel < self.maxZoomLevel: self.zoomlevel += 1 self.refresh() def zoomOut(self): if self.zoomlevel > 0: self.zoomlevel -= 1 self.refresh() def setBearing(self, bear): self.bearing = bear def setVelocity(self, vel): self.velocity = vel