import xml.etree.ElementTree as ET import coord_to_xy import math import sys from PIL import Image from PIL.ImageDraw import Draw from PIL.ImageFont import truetype fnt = truetype("/usr/share/fonts/TTF/DejaVuSans.ttf", 20) dateFnt = truetype("/usr/share/fonts/TTF/DejaVuSans.ttf", 40) zoom = 12 plaatjes = {} def degree_to_pix(lat_point,long_point,x_camera,y_camera,screenDim): (w,h) = screenDim (x_point,y_point)= coord_to_xy.degree_to_real_coord(math.radians(lat_point),math.radians(long_point),zoom) return(x_point-x_camera+w//2,y_point-y_camera+h//2) class item: def __init__(self,date): self.date = date def make_frames(): pass def dateToString(date): return(f"{date[0]} {date[1]} {date[2]}") class RemoveStation(item): def __init__(self,name,date): self.name=name self.date=date def toString(self): return(f"RS {self.name}\n{dateToString(self.date)}") class RemoveLine(item): def __init__(self,name,date): self.name=name self.date=date def toString(self): return(f"RL {self.name}\n{dateToString(self.date)}") class Station(item): def __init__(self,name,lat,long,date): self.name = name self.lat = lat self.long = long self.date = date self.animationLength = 2+len(name) def draw(self,d,x_real,y_real,screenDim): (x,y) = degree_to_pix(self.lat,self.long,x_real,y_real,screenDim) d.ellipse(((x-8,y-8),(x+8,y+8)),"black") d.ellipse(((x-4,y-4),(x+4,y+4)),"white") d.text((x+16, y-16), self.name, font=fnt, fill=(0,0,0)) def animate(self,d,x_real,y_real,screenDim,i): (x,y) = degree_to_pix(self.lat,self.long,x_real,y_real,screenDim) d.ellipse(((x-8,y-8),(x+8,y+8)),"black") if(i>0): d.ellipse(((x-4,y-4),(x+4,y+4)),"white") if(i>1): d.text((x+16,y-16), self.name[:i-1], font=fnt, fill=(0,0,0)) def cameraPos(self,i): return((self.lat,self.long)) def toString(self): return(f"S {self.lat} {self.long}\n{self.name}\n{dateToString(self.date)}") class Line(item): def __init__(self,name,color,date,start,end): self.name = name self.color=color self.date = date self.start = start self.end = end tree = ET.parse(name) trkseg = tree.getroot()[1][1] self.points = [] started = False for trkpt in trkseg: lat_point = trkpt.items()[0][1] lon_point = trkpt.items()[1][1] if((lat_point,lon_point)==end): break started = started or (lat_point,lon_point)==start if(started): self.points.append((float(lat_point),float(lon_point))) self.animationLength = (len(self.points)-1)//16 def parse(self,line): self.__init__(line[2:], "red") def draw(self,d,x_real,y_real,screenDim): first = True (prev_x,prev_y) = (0,0) for (lat_point,lon_point) in self.points: (x,y) = degree_to_pix(lat_point,lon_point,x_real,y_real,screenDim) if(not first): d.line(((x,y),(prev_x,prev_y)), fill='black', width=4, joint=None) first = False (prev_x,prev_y)=(x,y) def animate(self,d,x_real,y_real,screenDim,i): first = True (prev_x,prev_y) = (0,0) for j in range(1,i*16): (lat_point,lon_point) = self.points[j] (x,y) = degree_to_pix(lat_point,lon_point,x_real,y_real,screenDim) if(not first): d.line(((x,y),(prev_x,prev_y)), fill='black', width=4, joint=None) first = False (prev_x,prev_y)=(x,y) def cameraPos(self,i): return(self.points[i*16+1]) def toString(self): return(f"L {self.name}\n{dateToString(self.date)}\n{self.start[0]} {self.start[1]} {self.end[0]} {self.end[1]}") def parseItemFile(f): with open(f,'r') as fp: items = [] line = fp.readline() lineNumber =1 while line: if(line[0]=='S'): linesp = line.split() line1 = fp.readline() lineNumber+=1 line2 = fp.readline() lineNumber+=1 items.append(Station(line1[:-1],float(linesp[1]),float(linesp[2]),line2[:-1].split())) elif(line[0]=='L'): line1 = fp.readline() lineNumber+=1 line2 = fp.readline() lineNumber+=1 [startx,starty,endx,endy] = line2.split() items.append(Line(line[2:-1], 'red',line1[:-1].split(),(int(startx),int(starty)),(int(endx),int(endy)))) elif((line[0],line[1]) == ('R','S')): line1 = line line = fp.readline() lineNumber+=1 items.append(RemoveStation(line1[3:-1],line[:-1].split())) elif((line[0],line[1]) == ('R','L')): line1 = line line = fp.readline() lineNumber+=1 items.append(RemoveLine(line1[3:-1],line[:-1].split())) else: print(f"The symbol {line[0]} does not mean anything") line = fp.readline() lineNumber+=1 return items print(f"Could not open {f}") return [] def drawMap(lat,long,screenDim,Img): (x_tile,y_tile) = coord_to_xy.degree_to_coord(math.radians(lat),math.radians(long),zoom) (x_real,y_real)= coord_to_xy.degree_to_real_coord(math.radians(lat),math.radians(long),zoom) (x_tile_offset, y_tile_offset) = (x_real%256,y_real%256) (w,h) = screenDim tiles_width = math.ceil(w/256) tiles_height = math.ceil(h/256) for x in range(0,tiles_width): for y in range(0,tiles_height): tile_x = x+x_tile-tiles_width//2 tile_y = y+y_tile-tiles_height//2 if not ((tile_x,tile_y) in plaatjes): coord_to_xy.coord_to_download(tile_x,tile_y,zoom,"hey.png") plaatjes[(tile_x,tile_y)]=Image.open("hey.png") #afbeeldingen.append(Label(scherm)) upper_x = int(x*256-x_tile_offset-64) upper_y = int(y*256-y_tile_offset+24) Img.paste(plaatjes[(tile_x,tile_y)],box=(upper_x,upper_y)) #afbeeldingen[i].place(x=x*256-x_tile_offset,y=y*256-y_tile_offset) #omgezetPlaatjes.append(PhotoImage(plaatjes[i])) #afbeeldingen[i].configure(image=omgezetPlaatjes[i]) def createFrame(lat,long,stations,lines,animationItem,animationIndex,screenDim): (x_real,y_real)= coord_to_xy.degree_to_real_coord(math.radians(lat),math.radians(long),zoom) Img = Image.new(mode="RGBA", size=screenDim) draw = Draw(Img) #drawMap(lat,long,screenDim,Img) for line in lines.values(): line.draw(draw,x_real,y_real,screenDim) if(animationItem!=None and animationIndex!=None): animationItem.animate(draw,x_real,y_real,screenDim,animationIndex) for station in stations.values(): station.draw(draw,x_real,y_real,screenDim) if(animationItem!=None): draw.text((0,0), dateToString(animationItem.date), font=fnt, fill=(0,0,0)) return(Img) def coordDist(p1,p2): (lat1,long1)=p1 (lat2,long2)=p2 return(math.sqrt((lat1-lat2)**2+(long1-long2)**2)) def animate(items,screenDim): stations = {} lines = {} frame = 0 prevItem = None prevReverse = False count = 0 sys.stdout.write(f"Drawing item ") sys.stdout.flush() for item in items: count+=1 sys.stdout.write(str(count)+'/'+str(len(items))) sys.stdout.flush() reverse = False if(type(item) is RemoveStation): stations[item.name].date = item.date item = stations[item.name] reverse = True if(type(item) is RemoveLine): lines[item.name].date = item.date item = lines[item.name] reverse = True if(prevItem!=None): if(prevReverse): (lat1,long1) = prevItem.cameraPos(0) else: (lat1,long1) = prevItem.cameraPos(prevItem.animationLength-1) if(reverse): (lat2,long2) = item.cameraPos(prevItem.animationLength-1) else: (lat2,long2) = item.cameraPos(0) dist = coordDist((lat1,long1),(lat2,long2)) if(dist!=0): SLOWNESS = 10 vec1 = (lat2-lat1)/dist/SLOWNESS vec2 = (long2-long1)/dist/SLOWNESS for i in range(int(dist*SLOWNESS)): Img = createFrame(lat1+vec1*i,long1+vec2*i,stations,lines,None,None,screenDim) Img.save(f"out/frame-{frame:0>8}.png") frame+=1 if(reverse and type(item) is Station): stations.pop(item.name) if(reverse and type(item) is Line): lines.pop(item.name) n = item.animationLength for i in range(n): if(reverse): (lat,long) = item.cameraPos(n-1-i) Img = createFrame(lat,long,stations,lines,item,n-1-i,screenDim) Img.save(f"out/frame-{frame:0>8}.png") else: (lat,long) = item.cameraPos(i) Img = createFrame(lat,long,stations,lines,item,i,screenDim) Img.save(f"out/frame-{frame:0>8}.png") frame+=1 if(type(item) is Station): if(not reverse): stations[item.name] = item elif(type(item) is Line): if(not reverse): lines[item.name] = item prevItem = item prevReverse = reverse sys.stdout.write((len(str(count))+1+len(str(len(items))))*'\033[D \033[D') sys.stdout.flush()