# Code from # https://github.com/snorfalorpagus/ascii-world-map import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..'))) import json from functools import partial from shutil import get_terminal_size from shapely.geometry import shape, Point from shapely import ops import pyproj,math,os import rtree import curses,random,time from comrad.utils import Logger # import pandas as pd import numpy as np import warnings warnings.filterwarnings(action='ignore') PLACE_MARKER='@' BASEMAP_MARKER='_' PATH_MARKER='+' PROJECTION = 'webmerc' # # read the data into a list of shapely geometries # with open(os.path.join(os.path.dirname(__file__),"data/world-countries2.json")) as f: # data = json.load(f) default_places = { 'Cambridge':(52.205338,0.121817), 'Sydney':(-33.868820,151.209290), 'New York':(40.712776,-74.005974), 'Hong Kong':(22.278300,114.174700), 'Cape Town':(-33.9249, 18.4241), 'San Francisco':(37.774929,-122.419418), 'Honolulu':(21.306944,-157.858337), 'Tokyo':(35.689487,139.691711), 'Ushuaia':(-54.801910,-68.302948), 'Reykjavik':(64.126518,-21.817438) } # print_map(['Brazil','Netherlands','Thailand']) # print_map_simple(places) class Map(Logger): def __init__(self,stdscr): self.stdscr=stdscr self.base_df=None self.last_coords=None self.stdscr.clear() @property def width(self): return get_terminal_size().columns - 1 # from comrad.constants import CLI_WIDTH # return CLI_WIDTH @property def height(self): return get_terminal_size().lines - 1 # from comrad.constants import CLI_HEIGHT # return CLI_HEIGHT def precompute_basemap(self,countries=[]): data_fn=os.path.join( os.path.dirname(__file__), "data/world-countries.json" ) with open(data_fn) as f: data = json.load(f) geoms = [ shape(feature["geometry"]) for feature in data["features"] ] # transform the geometries into web mercator wgs84 = pyproj.Proj(init="EPSG:4326") webmerc = pyproj.Proj(proj=PROJECTION) t = partial(pyproj.transform, wgs84, webmerc) geoms = [ops.transform(t, geom) for geom in geoms] # create a spatial index of the geometries def gen(geoms): for n, geom in enumerate(geoms): yield n, geom.bounds, geom index = rtree.index.Index(gen(geoms)) # get the window size columns = self.width lines = self.height # allow for prompt at bottom # calculate the projected extent and pixel size # xmin, ymin = t(-180, -85) # xmax, ymax = t(180, 85) xmin, ymin = t(-170, -55) xmax, ymax = t(165, 75) pixel_width = (xmax - xmin) / columns pixel_height = (ymax - ymin) / lines land = "*" water = " " # stringl=[] # os.system('cls' if os.name == 'nt' else 'clear') ld=[] for line in range(lines): for col in range(columns): # get the projected x, y of the pixel centroid x = xmin + (col + 0.5) * pixel_width y = ymax - (line + 0.5) * pixel_height # check for a collision # self.log((col,line), (x,y),'???') objects = [n.object for n in index.intersection((x, y, x, y), objects=True)] value=None for geom in objects: value = geom.intersects(Point(x, y)) if value: d={'x':x,'y':y} #,'col':col,'row':line} ld+=[d] break self.stdscr.addstr(line,col,land if value else water) self.stdscr.refresh() # print(land if value else water, end="") # print("") # stringl+=['\n'] import pandas as pd df=pd.DataFrame(ld) # self.log(df,'!!') df['x_norm']=self.do_norm(df['x']) df['y_norm']=self.do_norm(df['y']) df.to_csv(os.path.join(os.path.dirname(data_fn),'basemap.csv'),index=False) # string = ''.join(stringl) # print(string) def do_norm(self,xcol): # self.log('<--',xcol) minn=xcol.min() maxx=xcol.max() import pandas as pd xcol=pd.Series([x + minn for x in xcol]) minn=xcol.min() maxx=xcol.max() res = [(x - minn) / (maxx - minn) for x in xcol] # self.log('-->',res) return res def add_base_map(self): # x,y coords import pandas as pd self.base_df=df=pd.read_csv(os.path.join(os.path.dirname(__file__),'data/basemap.csv')) # self.log(df) # convert to screen,coords coords = { ( int(x*self.width), int(y*self.height) ) for x,y in zip(df.x_norm,df.y_norm) } # self.log(coords) # stop for row in range(self.width): for line in range(self.height): if (row,line) in coords: self.stdscr.addstr(self.height - line,row,BASEMAP_MARKER) self.stdscr.refresh() # self.stdscr.getch() def run_print_map(self,places=[],labels=False,msg=[],offset_y=0): if msg: for i,x in enumerate(msg): x='--> '+x if i else x self.stdscr.addstr(i,0,x) self.stdscr.refresh() self.msg=msg if not places: return df = self.do_print_map(places) self.log(df,'!?!?!?') coords = { ( int(x*self.width), int(y*self.height) ) for x,y in zip(df.x_norm,df.y_norm) } self.log('coords:',coords) for x,y in coords: # lines? self.log('xy:',x,y,self.last_coords) if self.last_coords: lx,ly=self.last_coords went_north = bool(ly-y) went_east = bool(lx-x) self.log(f'{lx} -> {x} (x); {ly} -> {y} (y)') self.log(f'went east? {went_east}; went north? {went_north}') path_x = list(range(lx if lxx else x)+1)) path_y = list(range(ly if lyy else y)+1)) if lx>x: path_x.reverse() if ly>y: path_y.reverse() self.log('path_x:',path_x) self.log('path_y:',path_y) minlen=min(len(path_x), len(path_y)) hops_x = slice(path_x,minlen) hops_y = slice(path_y,minlen) lcoord_x=None lcoord_y=None for hop_x,hop_y in zip(hops_x,hops_y): self.log('hop_x',hop_x) self.log('hop_y',hop_y) hopmaxlen=max([len(hop_x),len(hop_y)]) hopcoords=[] for hi in range(hopmaxlen): hx=hop_x[hi] if hi