23
|
1 #!/usr/bin/python3
|
|
2 '''Find a safe landing space (i.e. in air, not above lava) near a cluster'''
|
|
3 import sys, math
|
|
4
|
|
5 from util import *
|
|
6 from bisect import insort
|
|
7
|
|
8 def usage():
|
|
9 print("""Usage: safe.py [-d n] [filename]
|
|
10 n is maximum distance of landing to some point in the cluster, default is 10.
|
|
11
|
|
12 Feed stdin with lines from the output of cluster.py, having produced
|
|
13 air.tsv with the same settings as the cluster input, and lava.tsv
|
|
14 with a lower-bound on Y of 0""")
|
|
15
|
|
16 n=10.0
|
|
17 if len(sys.argv)>1:
|
|
18 if sys.argv[1]=='-d':
|
|
19 sys.argv.pop()
|
|
20 n=float(sys.argv.pop(1))
|
|
21
|
|
22 if len(sys.argv)>1:
|
|
23 infile=open(sys.argv.pop(1))
|
|
24 else:
|
|
25 infile=sys.stdin
|
|
26
|
|
27 class Block:
|
|
28 '''Shared by Air and Lava,
|
|
29 holds points and columns.
|
|
30 Columns are dictionaries indexed by (x,z) coords,
|
|
31 value is upward-ordered list of pairs, closed intervals of y'''
|
|
32 def __init__(self,filename):
|
|
33 with open(filename,'r') as file:
|
|
34 self.readHeaders(file)
|
|
35 self.readPoints(file)
|
|
36
|
|
37 cc=self.columns={}
|
|
38 tc={}
|
|
39 for p in self.points:
|
|
40 k=(p[0],p[2])
|
|
41 y=p[1]
|
|
42 try:
|
|
43 yy=tc[k]
|
|
44 insort(yy,y)
|
|
45 except KeyError:
|
|
46 tc[k]=[y]
|
|
47 # convert to lists of intervals
|
|
48 for k,yy in tc.items():
|
|
49 tyy=[yy]
|
|
50 ii=[]
|
|
51 while True:
|
|
52 clean=True
|
|
53 for j,yy in enumerate(tyy):
|
|
54 if len(yy)==1+(yy[-1]-yy[0]):
|
|
55 ii.append((yy[0],yy[-1]))
|
|
56 else:
|
|
57 clean=False
|
|
58 for i in range(len(yy)-1):
|
|
59 if yy[i]+1!=yy[i+1]:
|
|
60 ii+=(yy[0],yy[i])
|
|
61 tyy=[yy[i+1:]]+tyy[j+1:]
|
|
62 break
|
|
63 if clean:
|
|
64 break
|
|
65 self.columns[k]=set(ii) # so we can merge later
|
|
66
|
|
67 def readPoints(self,file):
|
|
68 file.readline()
|
|
69 self.points=[[float(i) for i in l.split('\t')[2].split(',')] for l in file]
|
|
70
|
|
71 Block.readHeaders=readHeaders # from util
|
|
72
|
|
73 class Air(Block):
|
|
74 pass
|
|
75
|
|
76 A=Air('air.tsv')
|
|
77
|
|
78 class Lava(Block):
|
|
79 pass
|
|
80
|
|
81 L=Lava('lava.tsv')
|
|
82
|
|
83 def d(p1,p2):
|
|
84 dx=p1[0]-p2[0]
|
|
85 dz=p1[1]-p2[1]
|
|
86 dy=p1[2]-p2[2]
|
|
87 return math.sqrt((dx*dx)+(dy*dy)+(dz*dz))
|
|
88
|
|
89 def safety(p):
|
|
90 ka=[((a[0],a[2]),d(a,p)) for a in A.points if d(a,p)<=n]
|
|
91 return [(k,A.columns[k[0]],L.columns[k[0]]) for k in ka if k[0] in L.columns]
|
|
92
|
|
93 readHeaders(sys.modules['__main__'],infile,False)
|
|
94 for l in infile:
|
|
95 c=eval(l)
|
|
96 ss=[]
|
|
97 hits={}
|
|
98 misses=[]
|
|
99 for p in c:
|
|
100 ss=safety(p)
|
|
101 if ss:
|
|
102 for (k,a,l) in ss:
|
|
103 try:
|
|
104 (aa,ll)=hits[k]
|
|
105 aa.update(a)
|
|
106 ll.update(l)
|
|
107 except KeyError:
|
|
108 hits[k]=(a,l)
|
|
109 else:
|
|
110 misses.append(p)
|
|
111 print(c)
|
|
112 if hits:
|
|
113 print(' %s nearby landing columns'%len(hits))
|
|
114 for k in sorted(hits.keys(),key=lambda k:k[1]):
|
|
115 aa,ll=hits[k]
|
|
116 print("%s@%0.1f: %s %s"%(k[0],k[1],sorted(list(aa)),sorted(list(ll))))
|
|
117 else:
|
|
118 print(' No nearby landing zones')
|
|
119
|
|
120 if infile!=sys.stdin:
|
|
121 infile.close()
|