changeset 23:1670a33e3e6d

from markup
author Henry Thompson <ht@markup.co.uk>
date Sat, 29 May 2021 11:07:34 +0100
parents bd1db1ed4c25
children 6df2f6dcc809
files cluster.py safe.py
diffstat 2 files changed, 218 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cluster.py	Sat May 29 11:07:34 2021 +0100
@@ -0,0 +1,97 @@
+#!/usr/bin/python3
+'''Read a minutor block lockation tsv and resort it to show clusters'''
+import sys
+
+from util import *
+
+if len(sys.argv)==1 or sys.argv[1]=='-h':
+  print("""Usage: cluster.py [-h] [-c n] [-s] infile.tsv [outfile.tsv]
+           n is cluster diameter, default is 5
+           -s for strict circle distance, reduces number of candidates
+           default outfile is [infile]_c[n].tsv""")
+  exit(1)
+if sys.argv[1]=='-c':
+  sys.argv.pop(1)
+  n=float(sys.argv.pop(1))
+else:
+  n=5.0
+
+if sys.argv[1]=='-s':
+  sys.argv.pop(1)
+  strict=True
+else:
+  strict=False
+
+infile_name=sys.argv.pop(1)
+if len(sys.argv)>1:
+  outfile_name=sys.argv.pop(1)
+else:
+  outfile_name="%s_c%s.tsv"%(infile_name.split('.')[0],n)
+
+cc=[]
+
+with open(infile_name,'r') as infile:
+  with open(outfile_name,'w') as outfile:
+    l=infile.readline().rstrip()
+    print(l,file=outfile)
+    ff=PPAT.split(l)
+    (nr,ox,oy,oz)=intsMaybe(ff)
+    home=(float(ox),float(oy),float(oz))
+    et=ff[9]
+    l=infile.readline().rstrip()
+    print(l,file=outfile)
+    (orad,ymin,ymax)=intsMaybe(PPAT.split(l))
+    _=infile.readline()
+    for l in infile:
+      found=False
+      (_,td,qd)=l.rstrip().split('\t')
+      q=[float(i) for i in qd.split(',')]
+      td=float(td)
+      if strict and td>orad:
+        # Enforce a circular region, not square
+        print(td,orad,file=sys.stderr)
+        break
+      for c in cc:
+        for p in c:
+          if d(p,q)<=n:
+            c.append(q)
+            found=True
+            break
+        if found:
+          break
+      if not found:
+        cc.append([q])
+    oc=cc
+    cc=[] # lose
+    w=0
+    ow=-1
+    nc=[] # win
+    while True:
+      for i,c in enumerate(oc):
+        win=False
+        for p in c:
+          for g in oc[i+1:]:
+            for q in g:
+              if d(p,q)<=n:
+                win=True
+                w+=1
+                nc.append(c+g)
+                break
+            if win:
+              break
+          if win:
+            break
+        if not win:
+          cc.append(c)
+      print(len(cc),len(nc),ow,w,file=sys.stderr)
+      if ow==w:
+        break
+      ow=w
+      oc=nc
+      nc=[]
+    for c in sorted(cc,reverse=True,key=lambda x:len(x)):
+      print(c,file=outfile)
+    
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/safe.py	Sat May 29 11:07:34 2021 +0100
@@ -0,0 +1,121 @@
+#!/usr/bin/python3
+'''Find a safe landing space (i.e. in air, not above lava) near a cluster'''
+import sys, math
+
+from util import *
+from bisect import insort
+
+def usage():
+  print("""Usage:  safe.py [-d n] [filename]
+  n is maximum distance of landing to some point in the cluster, default is 10.
+  
+  Feed stdin with lines from the output of cluster.py, having produced
+  air.tsv with the same settings as the cluster input, and lava.tsv
+  with a lower-bound on Y of 0""")
+
+n=10.0
+if len(sys.argv)>1:
+  if sys.argv[1]=='-d':
+    sys.argv.pop()
+    n=float(sys.argv.pop(1))
+
+if len(sys.argv)>1:
+  infile=open(sys.argv.pop(1))
+else:
+  infile=sys.stdin
+
+class Block:
+  '''Shared by Air and Lava,
+  holds points and columns.
+  Columns are dictionaries indexed by (x,z) coords,
+  value is upward-ordered list of pairs, closed intervals of y'''
+  def __init__(self,filename):
+    with open(filename,'r') as file:
+      self.readHeaders(file)
+      self.readPoints(file)
+
+    cc=self.columns={}
+    tc={}
+    for p in self.points:
+      k=(p[0],p[2])
+      y=p[1]
+      try:
+        yy=tc[k]
+        insort(yy,y)
+      except KeyError:
+        tc[k]=[y]
+    # convert to lists of intervals
+    for k,yy in tc.items():
+      tyy=[yy]
+      ii=[]
+      while True:
+        clean=True
+        for j,yy in enumerate(tyy):
+          if len(yy)==1+(yy[-1]-yy[0]):
+            ii.append((yy[0],yy[-1]))
+          else:
+            clean=False
+            for i in range(len(yy)-1):
+              if yy[i]+1!=yy[i+1]:
+                ii+=(yy[0],yy[i])
+                tyy=[yy[i+1:]]+tyy[j+1:]
+            break
+        if clean:
+          break
+      self.columns[k]=set(ii) # so we can merge later
+
+  def readPoints(self,file):
+    file.readline()
+    self.points=[[float(i) for i in l.split('\t')[2].split(',')] for l in file]
+
+Block.readHeaders=readHeaders # from util
+
+class Air(Block):
+  pass
+
+A=Air('air.tsv')
+
+class Lava(Block):
+  pass
+
+L=Lava('lava.tsv')
+
+def d(p1,p2):
+  dx=p1[0]-p2[0]
+  dz=p1[1]-p2[1]
+  dy=p1[2]-p2[2]
+  return math.sqrt((dx*dx)+(dy*dy)+(dz*dz))
+
+def safety(p):
+  ka=[((a[0],a[2]),d(a,p)) for a in A.points if d(a,p)<=n]
+  return [(k,A.columns[k[0]],L.columns[k[0]]) for k in ka if k[0] in L.columns]
+
+readHeaders(sys.modules['__main__'],infile,False)
+for l in infile:
+  c=eval(l)
+  ss=[]
+  hits={}
+  misses=[]
+  for p in c:
+    ss=safety(p)
+    if ss:
+      for (k,a,l) in ss:
+        try:
+          (aa,ll)=hits[k]
+          aa.update(a)
+          ll.update(l)
+        except KeyError:
+          hits[k]=(a,l)
+    else:
+      misses.append(p)
+  print(c)
+  if hits:
+    print(' %s nearby landing columns'%len(hits))
+    for k in sorted(hits.keys(),key=lambda k:k[1]):
+      aa,ll=hits[k]
+      print("%s@%0.1f: %s %s"%(k[0],k[1],sorted(list(aa)),sorted(list(ll))))
+  else:
+    print(' No nearby landing zones')
+
+if infile!=sys.stdin:
+  infile.close()