def test_remove_loops6(): polya=Polygon(vvector([ Vertex(15,15),Vertex(15,10),Vertex(0,10),Vertex(0,0),Vertex(10,0),Vertex(10,15)])) polyb=polya.remove_loops() print polyb assert polyb==Polygon(vvector([ Vertex(10,10),Vertex(10,15),Vertex(15,15),Vertex(15,10)]))
def test_is_ccw(): polya=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) assert polya.is_ccw() polya=Polygon(vvector([ Vertex(0,0),Vertex(0,1),Vertex(1,1),Vertex(1,0)])) assert not polya.is_ccw()
def test_calc_area(): polya=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) assert abs(polya.calc_area()-1)<1e-5 polyb=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(2,1),Vertex(0,1)])) assert abs(polyb.calc_area()-1.5)<1e-5 polyc=Polygon(vvector([ Vertex(0,0),Vertex(2,0),Vertex(2,2),Vertex(1,0),Vertex(0,2)])) assert abs(polyc.calc_area()-2)<1e-5
def test_poly_eq(): polya=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) polyb=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) polyc=Polygon(vvector([ Vertex(0,1),Vertex(0,0),Vertex(1,0),Vertex(1,1)])) polyd=Polygon(vvector([ Vertex(0,1),Vertex(0,0),Vertex(1,0),Vertex(1,2)])) assert polya==polyb assert polya==polyc assert not (polya==polyd)
def test_inside_poly3(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(5,5),Vertex(0,10)])) assert polya.is_inside(Vertex(7,5)) assert polya.is_inside(Vertex(5,5)) #on edge assert polya.is_inside(Vertex(3,5)) assert not polya.is_inside(Vertex(5,7))
def test_polygon_intersect_line7(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(5,5),Vertex(0,10)])) ls=list(polya.intersect_line(Line(Vertex(-5,7),Vertex(15,7)))) print ls assert ls==[Line(Vertex(0,7),Vertex(4,7)), Line(Vertex(6,7),Vertex(10,7))]
def clean_up_polygon(poss): print "Clean poly:",poss def tov(merc): return Vertex(int(merc[0]),int(merc[1])) def fromv(v): return (v.get_x(),v.get_y()) vertices=[] last=None for pos in poss: #print pos if pos==last: continue last=pos vertices.append(tov(mapper.latlon2merc(mapper.from_str(pos),13))) poly=Polygon(vvector(vertices)) #print "calling tidy-up" shape=tidy_up_polygon(poly) ret=[] for poly in shape.get_polys(): #print "Got poly" vs=poly.get_vertices() out=[] for v in vs: out.append(mapper.to_str(mapper.merc2latlon(fromv(v),13))) ret.append(out) return ret
def clean_up_polygon(poss): print "Clean poly:", poss def tov(merc): return Vertex(int(merc[0]), int(merc[1])) def fromv(v): return (v.get_x(), v.get_y()) vertices = [] last = None for pos in poss: #print pos if pos == last: continue last = pos vertices.append(tov(mapper.latlon2merc(mapper.from_str(pos), 13))) poly = Polygon(vvector(vertices)) #print "calling tidy-up" shape = tidy_up_polygon(poly) ret = [] for poly in shape.get_polys(): #print "Got poly" vs = poly.get_vertices() out = [] for v in vs: out.append(mapper.to_str(mapper.merc2latlon(fromv(v), 13))) ret.append(out) return ret
def pypoly(data,kind="solid",mapmulti=None): assert data.count("\t")==0 xpos=1 ypos=data.count("\n") chs=dict() for c in data: if c=='\t': raise Exception("tab not allowed") if c=='\n': xpos=1 ypos-=1 else: if mapmulti: cs=mapmulti.get(c,[c]) else: cs=[c] for c in cs: if c!=' ': chs.setdefault(c,[]).append((xpos,ypos)) xpos+=1 lines=[] for c,poss in chs.items(): endpoints=[] for pos in poss: cnt=0 for aroundx in [-1,0,1]: for aroundy in [-1,0,1]: if aroundx==0 and aroundy==0: continue if (pos[0]+aroundx,pos[1]+aroundy) in poss: cnt+=1 if cnt==1 or cnt==0: endpoints.append(Vertex(*pos)) if len(endpoints)==1: endpoints.append(endpoints[0]) print len(endpoints) assert(len(endpoints)==2) lines.append((c,Line(endpoints[0],endpoints[1]))) lines.sort() #print "C,poss: ",lines outv=[] last=None for (n1,line1),(n2,line2) in izip(lines,lines[1:]+lines[:1]): if not ((line1.get_v2()-line2.get_v1()).taxilength()==1 or (line1.get_v2()-line2.get_v2()).taxilength()==1): line1=Line(line1.get_v2(),line1.get_v1()) if (line1.get_v2()-line2.get_v1()).taxilength()==1: outline=Line(line1.get_v1(),line2.get_v1()) elif (line1.get_v2()-line2.get_v2()).taxilength()==1: outline=Line(line1.get_v1(),line2.get_v2()) else: raise Exception("Unexpected error - bad input-data?") #print "Line: %s:%s"%(n1,outline) outv.append(outline.get_v1()) poly=Polygon(vvector(outv)) #if not poly.is_ccw(): # raise Exception("shouldn't be cw") if kind=="hole": poly.set_kind(Polygon.HOLE) return poly
def test_inside_poly1(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(0,10)])) assert not polya.is_inside(Vertex(5,11)) assert polya.is_inside(Vertex(5,5)) assert polya.is_inside(Vertex(0,5)) assert polya.is_inside(Vertex(5,10)) assert not polya.is_inside(Vertex(-1,5)) assert not polya.is_inside(Vertex(11,5))
def poly(points): last = None poly_coords = [] for coord in points: merc = mapper.latlon2merc(mapper.from_str(coord), 13) if merc == last: continue last = merc poly_coords.append(Vertex(int(merc[0]), int(merc[1]))) if len(poly_coords) >= 3: return Polygon(vvector(poly_coords)) return None
def poly(points): last=None poly_coords=[] for coord in points: merc=mapper.latlon2merc(mapper.from_str(coord),13) if merc==last: continue last=merc poly_coords.append(Vertex(int(merc[0]),int(merc[1]))) if len(poly_coords)>=3: return Polygon(vvector(poly_coords)) return None
def cleanup_poly(latlonpoints, name="?"): for minstep in [0, 10, 100, 1000, 10000, 100000]: mercpoints = [] lastmerc = None for latlon in latlonpoints: merc = mapper.latlon2merc(latlon, 13) if lastmerc != None: dist = math.sqrt( sum([(lastmerc[i] - merc[i])**2 for i in xrange(2)])) if dist < minstep: continue if merc == lastmerc: continue lastmerc = merc mercpoints.append(Vertex(int(merc[0]), int(merc[1]))) if len(mercpoints) < 50: break if len(mercpoints) <= 2: return None if mercpoints[0] == mercpoints[-1]: del mercpoints[-1] if len(mercpoints) <= 2: return None poly = Polygon(vvector(mercpoints)) if len(mercpoints) == 4: swapped = [mercpoints[1], mercpoints[0]] + mercpoints[2:] swappedpoly = Polygon(vvector(swapped)) #print "Found 4-corner area: ",name," areas:",swappedpoly.calc_area(),poly.calc_area() if abs(swappedpoly.calc_area()) > abs(1.1 * poly.calc_area()): print "Untwisting an area", name mercpoints = swapped poly = swappedpoly backtomerc = [ mapper.merc2latlon((m.get_x(), m.get_y()), 13) for m in mercpoints ] if poly.is_ccw(): return backtomerc else: #print "Reversed "+latlonpoints return reversed(backtomerc)
def test_first_entrance(): poly=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(0,10)])) res=list(poly.first_entrance(Line(Vertex(-5,5),Vertex(15,5)))) print "res:",res assert res[0]==Vertex(0,5) res=list(poly.first_entrance(Line(Vertex(15,5),Vertex(-5,5)))) print "res:",res assert res[0]==Vertex(10,5) assert res[0].get_x()==10
def cleanup_poly(latlonpoints,name="?"): for minstep in [0,10,100,1000,10000,100000]: mercpoints=[] lastmerc=None for latlon in latlonpoints: merc=mapper.latlon2merc(latlon,13) if lastmerc!=None: dist=math.sqrt(sum([(lastmerc[i]-merc[i])**2 for i in xrange(2)])) if dist<minstep: continue if merc==lastmerc: continue lastmerc=merc mercpoints.append(Vertex(int(merc[0]),int(merc[1]))) if len(mercpoints)<50: break if len(mercpoints)<=2: return None if mercpoints[0]==mercpoints[-1]: del mercpoints[-1] if len(mercpoints)<=2: return None poly=Polygon(vvector(mercpoints)) if len(mercpoints)==4: swapped=[mercpoints[1],mercpoints[0]]+mercpoints[2:] swappedpoly=Polygon(vvector(swapped)) #print "Found 4-corner area: ",name," areas:",swappedpoly.calc_area(),poly.calc_area() if abs(swappedpoly.calc_area())>abs(1.1*poly.calc_area()): print "Untwisting an area",name mercpoints=swapped poly=swappedpoly backtomerc=[mapper.merc2latlon((m.get_x(),m.get_y()),13) for m in mercpoints] if poly.is_ccw(): return backtomerc else: #print "Reversed "+latlonpoints return reversed(backtomerc)
def check_area(self,nr2tri): if len(self.triangles)==0: return totarea=0.0 for trinr in self.triangles: tri=nr2tri[trinr] coords=[] for v in tri.vobjs: print "Pos: %s"%((int(v.merc[0]),int(v.merc[1])),) coords.append(pyshapemerge2d.Vertex(int(v.merc[0]),int(v.merc[1]))) poly=Polygon(vvector(coords)) assert not poly.is_ccw() area=-poly.calc_area() print "Tri:%s area = %s"%([x.nr for x in tri.vobjs],area) totarea+=area print "Area should be: %s (since size = %d)"%(self.size*self.size,self.size) print "Area is: %s"%(totarea) assert abs(totarea-(self.size*self.size))<10.0*10.0
def get_weather(lat, lon): zoomlevel = 13 px, py = mapper.latlon2merc((lat, lon), zoomlevel) w = Weather() areas = weather_chart_areas.get_areas() insides = [] dists = [] for name, area in areas.items(): poly_coords = [] centerx = 0.0 centery = 0.0 for coord in area: x, y = mapper.latlon2merc(coord, zoomlevel) centerx += x + 0.0 centery += y + 0.0 poly_coords.append(Vertex(int(x), int(y))) if len(poly_coords) < 3: print "Weather area %s has few points: %s " % (name, area) continue centerx /= len(poly_coords) centery /= len(poly_coords) cdist = (centerx - px)**2 + (centery - py)**2 poly = Polygon(vvector(poly_coords)) if poly.is_inside(Vertex(int(px), int(py))): cdist *= 1e-3 insides.append((cdist, name, area)) #print "insides:",insides insides.sort() dist, name, area = insides[0] if dist > 20000**2: return None w.weather_area = name mainarea, rest = name.split("_") part = rest[:-2] seg = rest[-2:] try: fc = get_parsed_weather() except Exception, cause: print "Couldn't fetch weather: ", cause #there's no weather service at certain times. return None
def get_weather(lat,lon): zoomlevel=13 px,py=mapper.latlon2merc((lat,lon),zoomlevel) w=Weather() areas=weather_chart_areas.get_areas() insides=[] dists=[] for name,area in areas.items(): poly_coords=[] centerx=0.0 centery=0.0 for coord in area: x,y=mapper.latlon2merc(coord,zoomlevel) centerx+=x+0.0 centery+=y+0.0 poly_coords.append(Vertex(int(x),int(y))) if len(poly_coords)<3: print "Weather area %s has few points: %s "%(name,area) continue centerx/=len(poly_coords) centery/=len(poly_coords) cdist=(centerx-px)**2+(centery-py)**2 poly=Polygon(vvector(poly_coords)) if poly.is_inside(Vertex(int(px),int(py))): cdist*=1e-3 insides.append((cdist,name,area)) #print "insides:",insides insides.sort() dist,name,area=insides[0] if dist>20000**2: return None w.weather_area=name mainarea,rest=name.split("_") part=rest[:-2] seg=rest[-2:] try: fc=get_parsed_weather() except Exception,cause: print "Couldn't fetch weather: ",cause #there's no weather service at certain times. return None
def get_polygons_around(lat,lon,polys): zoomlevel=13 px,py=mapper.latlon2merc((lat,lon),zoomlevel) insides=[] for space in polys: poly_coords=[] for coord in space['points']: x,y=mapper.latlon2merc(mapper.from_str(coord),zoomlevel) poly_coords.append(Vertex(int(x),int(y))) if len(poly_coords)<3: #print "Space %s has few points: %s "%(space['name'],space['points']) continue poly=Polygon(vvector(poly_coords)) #print "Checking if inside poly:",space if poly.is_inside(Vertex(int(px),int(py))): insides.append(space) #print "Is inside" else: pass#print "Is NOT inside" return insides
def get_borders(pcountry): #print "Getting for",pcountry global borders if not borders: if not os.path.exists("fplan/extract/lands.bin"): if os.system("bunzip2 fplan/extract/lands.bin.bz2")!=0: raise Exception("Couldn't unbzip2 lands.bin.bz2") f=open("fplan/extract/lands.bin") tborders=pickle.load(f) f.close() out=dict() for country,parts in tborders.items(): outparts=[] tot=0 for part in parts: outpart=[] poly_coords=[] last=None for coord in part: merc=mapper.latlon2merc(mapper.from_str(coord),13) if merc==last: continue last=merc outpart.append(merc) tot+=1 poly_coords.append(Vertex(int(merc[0]),int(merc[1]))) assert len(outpart)>=3 if outpart[0]==outpart[-1]: outpart=outpart[:-1] poly_coords=poly_coords[:-1] poly=Polygon(vvector(poly_coords)) assert poly.is_ccw() outparts.append(outpart) #print "Parts in ",country,len(outparts),tot out[country]=outparts borders=out #if pcountry!="sweden": # raise Exception("Debug, just allow sweden for now. just remove this after.") return borders[pcountry]
def get_borders(pcountry): #print "Getting for",pcountry global borders if not borders: if not os.path.exists("fplan/extract/lands.bin"): if os.system("bunzip2 fplan/extract/lands.bin.bz2") != 0: raise Exception("Couldn't unbzip2 lands.bin.bz2") f = open("fplan/extract/lands.bin") tborders = pickle.load(f) f.close() out = dict() for country, parts in tborders.items(): outparts = [] tot = 0 for part in parts: outpart = [] poly_coords = [] last = None for coord in part: merc = mapper.latlon2merc(mapper.from_str(coord), 13) if merc == last: continue last = merc outpart.append(merc) tot += 1 poly_coords.append(Vertex(int(merc[0]), int(merc[1]))) assert len(outpart) >= 3 if outpart[0] == outpart[-1]: outpart = outpart[:-1] poly_coords = poly_coords[:-1] poly = Polygon(vvector(poly_coords)) assert poly.is_ccw() outparts.append(outpart) #print "Parts in ",country,len(outparts),tot out[country] = outparts borders = out #if pcountry!="sweden": # raise Exception("Debug, just allow sweden for now. just remove this after.") return borders[pcountry]
def get_polygons_on_line(latlon1,latlon2,polys): zoomlevel=13 px1,py1=mapper.latlon2merc(latlon1,zoomlevel) px2,py2=mapper.latlon2merc(latlon2,zoomlevel) line=Line(Vertex(int(px1),int(py1)),Vertex(int(px2),int(py2))) crosses=[] for space in polys: poly_coords=[] for coord in space['points']: x,y=mapper.latlon2merc(mapper.from_str(coord),zoomlevel) poly_coords.append(Vertex(int(x),int(y))) if len(poly_coords)<3: #print "Space %s has few points: %s "%(space['name'],space['points']) continue poly=Polygon(vvector(poly_coords)) #print "Checking if intersect poly:",space if len(poly.intersect_line(line))>0: crosses.append(space) #print "Is crossing" else: pass#print "Is NOT crossing" return crosses
def test_shape_eq(): assert 0 polya1=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) polya2=Polygon(vvector([ Vertex(2,0),Vertex(3,0),Vertex(3,1),Vertex(2,1)])) polyb1=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) polyb2=Polygon(vvector([ Vertex(2,1),Vertex(2,0),Vertex(3,0),Vertex(3,1)])) polyc1=Polygon(vvector([ Vertex(0,0),Vertex(1,0),Vertex(1,1),Vertex(0,1)])) polyc2=Polygon(vvector([ Vertex(2,1),Vertex(2,0),Vertex(4,0),Vertex(3,1)])) shape_a=Shape("a",pvector([polya1,polya2])) shape_b=Shape("b",pvector([polyb1,polyb2])) shape_c=Shape("c",pvector([polyc1,polyc2])) assert shape_a==shape_b assert not (shape_a==shape_c)
def parse_page(parser,pagenr,kind="TMA",last_sector=dict()): if kind=="TMA": thirdcols=["ATC unit","AFIS unit"] elif kind=="sector": thirdcols=["FREQ"] elif kind=="R": thirdcols=["Remarks (nature of hazard,"] else: raise Exception("Bad kind") page=parser.parse_page_to_items(pagenr) items=page.items #print "Items:",pitems #print "Possible Areas:" headings=[] for item in items: if item.text==None: continue item.text=item.text.strip() if item.text=="": continue if item.text=="Name": continue if item.y1<25 and item.text in (["Lateral limits","Vertical limits"]+thirdcols): headings.append(item) headings.sort(key=lambda x:x.x1) #print "found candidates:",zone_candidates if len(headings)==0: return [] avg_heading_y=sum(h.y1 for h in headings)/float(len(headings)) uprint("Found headings:",headings) zone_candidates=[] for item in items: if item.text==None or item.text.strip()=="": continue if item.text.strip().startswith("AMDT"): continue if item.text.strip().startswith("The LFV Group"): continue if re.match(ur"\s*LFV\s*AIRAC\s*AMDT\s*\d+/\d+\s*",item.text): continue if item.text.strip()=="LFV": continue if item.text.count('Terminal Information Areas'): continue if item.text.strip().startswith("AIRAC"): continue if kind=="R" and not is_r_or_danger_area_name(item.text.strip()): continue if item.y1>avg_heading_y+1 and item.x1<12 and not item.text in ["Name",'None',"LFV"]: if item.text.count("Established") or item.text.count(u'TROLLHÄTTAN TWR') or item.text.count(u'and/or SÅTENÄS') or item.text.count(u'TWR/TMC') or item.text.strip().endswith("TWR") or item.text.strip().endswith("TWR."): continue if item.text.count("operational hours") or item.text.count("See AIP DENMARK"): continue if item.text.count("hours of"): continue if item.text.count("Upper limit"): continue if item.text.count("that part") or item.text.count("coincides"): continue if item.text.count(u'Danger area EK D395 and') or item.text.count(u'D396 are situated within') or item.text.strip()=="TMA": continue if item.text.count(u'ÖSTGÖTA TMC is closed') or item.text.count(u'and SKAVSTA TWR is') or item.text.strip()=='open.': continue if item.text.count("SAT 0530"): continue if item.text.strip()=='OPS': continue if item.text.strip()==u'ÖSTGÖTA TMC:': continue if item.text.count(u'is open') or item.text.count('is closed'): continue if item.text.count('MON-FRI') or item.text.count('2150'): continue lines2=page.get_lines(page.get_partially_in_rect(12,item.y1+0.2,40,item.y2-0.2)) if len(lines2): zone_candidates.append(item) uprint("Found cands:",zone_candidates) zone_candidates.sort(key=lambda x:x.y1) for zone in zone_candidates: #uprint("Zone:",zone) #assert not zone.text.count("AOR") assert not zone.text.count("FIR") uprint("Headings:",headings) print "Pagenr:",pagenr assert len(headings)==3 ret=[] for i in xrange(len(zone_candidates)): d=dict() cand=zone_candidates[i] if i<len(zone_candidates)-1: nextcand=zone_candidates[i+1] else: nextcand=None y1=cand.y1-0.25 y2=100 if nextcand: y2=nextcand.y1-0.75 for j in xrange(len(headings)): head=headings[j] if j<len(headings)-1: nexthead=headings[j+1] else: nexthead=None x1=head.x1 x2=head.x2 if j==len(headings)-1: x1=headings[j-1].x2+3 x2=100 lines=page.get_lines(page.get_partially_in_rect(x1,y1,x2,y2,xsort=True,ysort=True)) #print ("Parsed %s y,%d-%d, %s: <%s>\n\n"%(cand.text,y1,y2,head.text,lines)).encode('utf8') d[head.text]=lines if kind=="R": if y2==100: y2=y1+3 d['name']=" ".join(x.strip() for x in filter_head_foot(page.get_lines(page.get_partially_in_rect(0,y1,10,y2,xsort=True,ysort=True)))) else: d['name']=cand.text.strip() ret.append(d) allow_head=2 print "Doing fixups--------------------------------------------------" tret=[] for x in ret: #print "Fixing up",x,"allow:",allow_head area="".join(x['Lateral limits']).strip() if allow_head==2 and area!="" and x['name'].strip()!="": allow_head=1 if allow_head!=1: if len(tret): tret[-1]['Lateral limits']+=x['Lateral limits'] tret[-1]['Vertical limits']+=x['Vertical limits'] else: tret.append(x) if allow_head==1: allow_head=0 if not area.endswith('-') and area!="": allow_head=2 #print " Fixed up up",x ret=tret for line in ret: print "Fixed:",line['name']," = ",line['Lateral limits'],line['Vertical limits'] out=[] for d in ret: pa=dict() curname=d['name'] if curname.count(u'Förteckning över'): continue print "D:",d arealines=[l for l in d['Lateral limits'] if l.strip()!=""] last_coord_idx=None #uprint("D:<%s> (area:%s)"%(d,arealines)) if 'FREQ' in d: freqs=[("SWEDEN CONTROL",float(x)) for x in re.findall(r"\d{3}\.\d{3}","\n".join(d['FREQ']))] #print "Parsed freqs:",freqs if freqs: last_sector['freqs']=freqs if kind=='sector': m=re.match(r"ES[A-Z]{2}\s*ACC\s*sector\s*([0-9a-zA-Z]*)",d['name']) if m: last_sector['major']=d['name'] last_sector['majorsector'],=m.groups() if len(arealines)==0: last_sector['name']=d['name'] continue if d['name'].count("Control Area and Upper Control Area"): continue if d['name'].count("SUECIA CTA"): continue if d['name'].count("SUECIA UTA"): continue m=re.match(r"([0-9a-zA-Z]*)(:.*)",d['name']) if m and 'majorsector' in last_sector: sectorname,sub=m.groups() if sectorname==last_sector['majorsector']: d['name']=last_sector['major']+sub #uprint("Fixed up name: ",d['name']) #print "Arealines:",arealines assert len(arealines) if arealines[0].strip()=="Danger area EK D395 and D396 are": arealines=arealines[1:] if arealines[0].strip()=="situated within TMA": arealines=arealines[1:] if arealines==u'Förteckning över CTA / Lists of CTA' or arealines=='Lateral limits': continue for idx in xrange(len(arealines)): if arealines[idx].lower().startswith("established"): last_coord_idx=idx pa['established']=" ".join(l for l in arealines[idx:]) break if arealines[idx].lower().startswith("danger area"): last_coord_idx=idx break if arealines[idx].strip()=="LFV": last_coord_idx=idx break if last_coord_idx==None: last_coord_idx=len(arealines) #uprint("ARealines:",arealines) #uprint("Last coord:",arealines[last_coord_idx-1]) if len(arealines)>last_coord_idx: if arealines[last_coord_idx-1:last_coord_idx+1]==[u'571324N 0161129E -', u'Established during operational hours of']: arealines[last_coord_idx-1]=arealines[last_coord_idx-1].strip("-") #uprint("Last fixed:",arealines[last_coord_idx-1]) assert not arealines[last_coord_idx-1].strip().endswith("-") #for idx in xrange(last_coord_idx-1): # print "arealine: <%s>"%(arealines[idx].strip(),) # assert arealines[idx].strip().endswith("-") or arealines[idx].strip().endswith("to") vertlim=u" ".join(d['Vertical limits']) if vertlim.strip()=="": #print "Object with no vertical limits: %s"%(repr(d['name']),) continue if d['name']=='Control Area': continue uprint("Vertlim: ",vertlim) heightst=re.findall(r"(FL\s*\d{3})|(\d+\s*ft\s*(?:\s*/\s*\d+\s*.\s*GND)?(?:\s*GND)?)|(GND)|(UNL)",vertlim) uprint("Height candidates:",heightst) heights=[] for fl,ht,gnd,unl in heightst: if fl: heights.append(fl) if ht: heights.append(ht.strip()) if gnd: heights.append(gnd.strip()) if unl: heights.append(unl.strip()) uprint("heights for ",d['name'],":",repr(heights)) if len(heights)==0 and d['name']==u'GÖTEBORG TMA': heights=['GND','FL95'] if len(heights)==1 and d['name']==u'Göteborg TMA': heights=['4500','FL95'] assert len(heights)==2 ceiling=heights[0].strip() floor=heights[1].strip() pa['name']=d['name'] pa['floor']=floor pa['ceiling']=ceiling if mapper.parse_elev(floor)>=9500: continue #uprint("Arealines:\n================\n%s\n============\n"%(arealines[:last_coord_idx])) #print pa areacoords=" ".join(arealines[:last_coord_idx]) pa['points']=parse_coord_str(areacoords) vs=[] for p in pa['points']: #print "from_str:",repr(p) x,y=mapper.latlon2merc(mapper.from_str(p),13) vs.append(Vertex(int(x),int(y))) p=Polygon(vvector(vs)) if p.calc_area()<=30*30: pass#print pa #print "Area:",p.calc_area() assert p.calc_area()>30*30 #print "Area: %f"%(p.calc_area(),) #print "Point-counts:",len(pa['points']) for p in pa['points']: assert p.count(",")==1 pa['type']=kind for thirdcol in thirdcols: if thirdcol in d: atc=d[thirdcol] break else: raise Exception("missing thirdcol") #print "ATc: <%s>"%(repr(atc),) freqs=[(y,float(x)) for x,y in re.findall(r"(\d{3}\.\d{3})\s*MHz\n(.*)","\n".join(atc))] if not freqs: freqs=last_sector.get('freqs',[]) #print repr(freqs) pa['freqs']=freqs #uprint("Cleaning up ",pa['name']) for cleaned in clean_up_polygon(list(pa['points'])): d=dict(pa) #print "cleaned",cleaned for i,tup in enumerate(cleaned): assert type(tup)==str latlon=mapper.from_str(tup) lat,lon=latlon assert lat>=-85 and lat<=85 d['points']=cleaned #uprint("cleaned:",pa['name'],len(cleaned),cleaned) #print "name:",d['name'] #print "cleaned points:",d['points'] #print "from:",areacoords #raise Exception() out.append(d) #if pa['name'].lower().count("esrange"): # print "Exit esrange" # sys.exit(1) return out
def gen_bsptree_lookup(data): r=dict() lookup_points=['obstacles', 'airfields', 'sig_points'] for look in lookup_points: items=data.get(look,None) if True: bspitems=[] for item in items: try: bspitems.append(BspTree.Item( mapper.latlon2merc(mapper.from_str(item['pos']),13),item) ) except Exception: print item raise #print "Items for bsptree",items bsp=BspTree(bspitems) #assert len(bsp.getall())==len(items) #after=sorted(set(x['name'] for x in bsp.getall())) #before=sorted(set(x['name'] for x in obsts)) #print after,"\n-------------------\n\n",before #assert after==before #print "same before as after" r[look]=bsp del item del items del bspitems del bsp lookup_spaces=['airspaces','firs'] for look in lookup_spaces: spaces=data.get(look,None) if spaces!=None: bbitems=[] zoomlevel=13 for space in spaces: poly_coords=[] bb=BoundingBox(1e30,1e30,-1e30,-1e30) for coord in space['points']: x,y=mapper.latlon2merc(mapper.from_str(coord),zoomlevel) bb.x1=min(bb.x1,x) bb.x2=max(bb.x2,x) bb.y1=min(bb.y1,y) bb.y2=max(bb.y2,y) poly_coords.append(Vertex(int(x),int(y))) if len(set(poly_coords))<3: continue print "Poly" poly=Polygon(vvector(poly_coords)) print "polydone" #print "Item:",space bbitems.append( BBTree.TItem(bb,(poly,space))) #if poly.is_inside(Vertex(int(px),int(py))): # insides.append(space) bbt=BBTree(bbitems,0.5) r[look]=bbt return r
def vistest_merge_shapes(): for x in xrange(10): x=5 poly_a=Polygon(vvector([ Vertex(0+x,0),Vertex(2+x,0), Vertex(2+x,2),Vertex(0+x,2)])) poly_b=Polygon(vvector([ Vertex(1,1),Vertex(3,1), Vertex(3,4),Vertex(1,4)])) shape_a=Shape("shape_a",poly_a) shape_b=Shape("shape_b",poly_b) # OOOO # OOOO # OOOOOO # OOOO # OOOO bo=BooleanOp() #print "Shape_a,shape_b: ",shape_a,shape_b bo.step1_add_lines(shape_a,shape_b) bo.step2_intersect_lines() splitset=set([NondirLine(x.get_v1(),x.get_v2()) for x in bo.dbg_step2_get_split_lines()]) #print "Split result: %s"%("\n".join(str(l) for l in splitset),) assert not NondirLine(Vertex(0,2),Vertex(2,2)) in splitset bo.step3_create_edges() edges=list(bo.dbg_step3_and_4_get_edges()) nondiredges=list(NondirLine(x.get_v1(),x.get_v2()) for x in bo.dbg_step3_and_4_get_edges()) sqs=[] cnt=0 #print "Edges: %s"%(edges,) for edge in edges: line=Line(edge.get_v1(),edge.get_v2()) r=(25*cnt)%128+128 g=(128*cnt)%128+128 b=(64*cnt)%128+128 sqs.append(visualize.Line( line.get_v1().get_x(), line.get_v1().get_y(), line.get_v2().get_x(), line.get_v2().get_y(), (r,g,b))) sqs.append(visualize.Square( line.get_v1().get_x()-0.1, line.get_v1().get_y()-0.1, line.get_v1().get_x()+0.1, line.get_v1().get_y()+0.1, (r,g,b))) cnt+=1 draw_things(sqs) assert not (NondirLine(Vertex(0,2),Vertex(2,2)) in nondiredges) bo.step4_eliminate_deadends() bo.step5_create_cells() bo.step6_determine_cell_cover() bas=BooleanOrStrategy() bo.step7_classify_cells(bas) for cell in list(bo.dbg_step5_get_cells()): sqs=[] for edge in list(cell.dbg_get_edges()): line=Line(edge.get_v1(),edge.get_v2()) sqs.append(visualize.Line( line.get_v1().get_x(), line.get_v1().get_y(), line.get_v2().get_x(), line.get_v2().get_y(), (255,0,0))) #print "Cell cover:",list(cell.get_shapes()) #print "Cell type:",cell.get_classification() draw_things(sqs) bo.step8_merge_cells() bo.step9_calc_result() shape=bo.step9_get_result() polys=list(shape.get_polys()) plines=set() for poly in polys: #print "Poly: %s %s"%(poly.get_kind_str(),list(poly.get_lines())) plines=plines.union(frozenset(poly.get_lines())) sqs=[] edges=set(bo.dbg_step3_and_4_get_edges()) for line in plines: sqs.append(visualize.Line( line.get_v1().get_x(), line.get_v1().get_y(), line.get_v2().get_x(), line.get_v2().get_y(), (0,200,0))) draw_things(sqs)
def vistest_add_lines(): #print "Press any key when debugger ready" #raw_input() bo=BooleanOp() poly_a=Polygon(vvector([ Vertex(0,0),Vertex(2,0), Vertex(2,2),Vertex(0,2)])) poly_b=Polygon(vvector([ Vertex(1,1),Vertex(3,1), Vertex(3,3),Vertex(1,3)])) shape_a=Shape("shape_a",poly_a) shape_b=Shape("shape_b",poly_b) #print "Shape_a,shape_b: ",shape_a,shape_b bo.step1_add_lines(shape_a,shape_b) bo.step2_intersect_lines() lines=list(bo.dbg_step2_get_split_lines()) #print "The found, split lines:" #print "\n".join(str(x) for x in lines) assert len(lines)==12 assert Line(Vertex(0,0),Vertex(2,0)) in lines assert Line(Vertex(2,0),Vertex(2,1)) in lines assert Line(Vertex(2,1),Vertex(2,2)) in lines assert Line(Vertex(2,2),Vertex(1,2)) in lines assert Line(Vertex(1,2),Vertex(0,2)) in lines assert Line(Vertex(0,2),Vertex(0,0)) in lines assert Line(Vertex(1,1),Vertex(2,1)) in lines assert Line(Vertex(2,1),Vertex(3,1)) in lines assert Line(Vertex(3,1),Vertex(3,3)) in lines assert Line(Vertex(3,3),Vertex(1,3)) in lines assert Line(Vertex(1,3),Vertex(1,2)) in lines assert Line(Vertex(1,2),Vertex(1,1)) in lines bo.step3_create_edges() edges=bo.dbg_step3_and_4_get_edges() edgelines=dict((Line(edge.get_v1(),edge.get_v2()),edge) for edge in edges) assert set(edgelines.keys())==set(lines) for key,edge in edgelines.items(): if key.get_v1().get_y()==key.get_v2().get_y(): assert edge.get_k_approx()==0.0 assert edge.get_is_vertical()==False else: #vertical assert edge.get_k_approx()==0.0 #also for vertical but: assert edge.get_is_vertical()==True bo.step4_eliminate_deadends() edges=bo.dbg_step3_and_4_get_edges() edgelines=dict((Line(edge.get_v1(),edge.get_v2()),edge) for edge in edges) assert set(edgelines.keys())==set(lines) for key,edge in edgelines.items(): if key.get_v1().get_y()==key.get_v2().get_y(): assert edge.get_k_approx()==0.0 assert edge.get_is_vertical()==False else: #vertical assert edge.get_k_approx()==0.0 #also for vertical but: assert edge.get_is_vertical()==True bo.step5_create_cells() cells=list(bo.dbg_step5_get_cells()) #print "Cells:\n","\n".join(str(x) for x in cells) def lineset(*vertices): s=set() for v1,v2 in zip(vertices,vertices[1:]+vertices[:1]): s.add(NondirLine(v1,v2)) return frozenset(s) def lineset2(*vertices): s=set() for v1,v2 in zip(vertices,vertices[1:]+vertices[:1]): s.add(Line(v1,v2)) return frozenset(s) facit_cells={ lineset(Vertex(0,0),Vertex(2,0),Vertex(2,1),Vertex(3,1), Vertex(3,3),Vertex(1,3),Vertex(1,2),Vertex(0,2)):"outline", lineset(Vertex(1,1),Vertex(2,1),Vertex(2,2),Vertex(1,2)):"center", lineset(Vertex(2,1),Vertex(3,1),Vertex(3,3),Vertex(1,3), Vertex(1,2),Vertex(2,2)):"upper_right", lineset(Vertex(0,0),Vertex(2,0),Vertex(2,1),Vertex(1,1), Vertex(1,2),Vertex(0,2)):"lower_left" } #print "Facit cells","\n".join(str(x) for x in facit_cells.keys()) assert len(cells)==4 for cell in cells: edges=cell.dbg_get_edges() edgelines=set(NondirLine(edge.get_v1(),edge.get_v2()) for edge in edges) if not (edgelines in facit_cells.keys()): sqs=[] for line in edgelines: sqs.append(visualize.Line( line.get_v1().get_x(), line.get_v1().get_y(), line.get_v2().get_x(), line.get_v2().get_y(), (255,0,0))) draw_things(sqs) bo.step6_determine_cell_cover() cells=list(bo.dbg_step5_get_cells()) for cell in cells: edges=cell.dbg_get_edges() edgelines=frozenset(NondirLine(edge.get_v1(),edge.get_v2()) for edge in edges) shapes=list(cell.get_shapes()) realcellname=facit_cells[edgelines] facit_cell_shapes={ 'lower_left':('shape_a',), 'center':('shape_a','shape_b'), 'upper_right':('shape_b',), 'outline':() } #print "Facit:",facit_cell_shapes[realcellname] #print "Actual:",tuple(shapes) assert facit_cell_shapes[realcellname]==tuple(shapes) #print "Cell: %s, shapes: %s"%(realcellname,", ".join(shapes)) bas=BooleanOrStrategy() bo.step7_classify_cells(bas) cells=list(bo.dbg_step5_get_cells()) for cell in cells: edges=cell.dbg_get_edges() edgelines=frozenset(NondirLine(edge.get_v1(),edge.get_v2()) for edge in edges) shapes=list(cell.get_shapes()) realcellname=facit_cells[edgelines] facit_cell_kind={ 'lower_left':'SOLID', 'center':'SOLID', 'upper_right':'SOLID', 'outline':'VOID' } #print "Cell %s classification: %s"%(realcellname,cell.get_classification()) assert cell.get_classification()==facit_cell_kind[realcellname] bo.step8_merge_cells() cells=list(bo.dbg_step5_get_cells()) def lookup_cellname(cell): edges=cell.dbg_get_edges() edgelines=frozenset(NondirLine(edge.get_v1(),edge.get_v2()) for edge in edges) shapes=list(cell.get_shapes()) realcellname=facit_cells[edgelines] return realcellname for cell in cells: facit_cell_merged={ 'lower_left':0, 'center':0, 'upper_right':0, 'outline':1 } realcellname=lookup_cellname(cell) #print "Cell %s merged_poly: %s, class: %s"%(realcellname,cell.get_merged_poly(),cell.get_classification()) #print "%s: Neighbors:"%realcellname," ".join(lookup_cellname(ce) for ce in cell.get_neighbors()) assert cell.get_merged_poly()==facit_cell_merged[realcellname] bo.step9_calc_result() shape=bo.step9_get_result() polys=list(shape.get_polys()) assert len(polys)==1 poly,=polys "Poly: %s %s"%(poly.get_kind_str(),list(poly.get_lines())) assert poly.get_kind_str()=="SOLID" plines=frozenset(poly.get_lines()) should=lineset2(Vertex(0,0),Vertex(2,0),Vertex(2,1),Vertex(3,1), Vertex(3,3),Vertex(1,3),Vertex(1,2),Vertex(0,2)) #print "Is: ",plines #print "Should: ",should assert plines==should sqs=[] for line in plines: sqs.append(visualize.Line( line.get_v1().get_x(), line.get_v1().get_y(), line.get_v2().get_x(), line.get_v2().get_y(), (255,0,0))) draw_things(sqs)
def test_polygon_intersect_line22(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,5),Vertex(5,5),Vertex(5,10),Vertex(0,10)])) ls=list(polya.intersect_line(Line(Vertex(0,5),Vertex(10,6)))) print ls assert ls==[Line(Vertex(0,5),Vertex(5,6))]
def test_inside_poly2(): polya=Polygon(vvector([ Vertex(0,0),Vertex(0,5),Vertex(10,0),Vertex(10,10),Vertex(0,10)])) assert polya.is_inside(Vertex(5,5))
pa['floor'] = floor pa['ceiling'] = ceiling if mapper.parse_elev(floor) >= 9500: continue #uprint("Arealines:\n================\n%s\n============\n"%(arealines[:last_coord_idx])) #print pa areacoords = " ".join(arealines[:last_coord_idx]) pa['points'] = parse_coord_str(areacoords) vs = [] for p in pa['points']: #print "from_str:",repr(p) x, y = mapper.latlon2merc(mapper.from_str(p), 13) vs.append(Vertex(int(x), int(y))) p = Polygon(vvector(vs)) if p.calc_area() <= 30 * 30: pass #print pa #print "Area:",p.calc_area() assert p.calc_area() > 30 * 30 #print "Area: %f"%(p.calc_area(),) #print "Point-counts:",len(pa['points']) for p in pa['points']: assert p.count(",") == 1 pa['type'] = kind for thirdcol in thirdcols: if thirdcol in d: atc = d[thirdcol] break else: raise Exception("missing thirdcol")
class UserData(object): def have_any(self): return not self.empty def __init__(self, user, orders=None): #print "Loading userdata for ",user self.user = user self.log = [] self.points = dict() self.spaces = dict() self.pointslookup = dict() self.spaceslookup = dict() self.empty = True zoomlevel = 13 pointtypes = ['obstacles', 'airfields', 'sigpoints'] spacestypes = ['airspaces', 'firs'] for pointtype in pointtypes: self.points[pointtype] = [] for spacetype in spacestypes: self.spaces[spacetype] = [] if orders == None: orders = [] for csets in meta.Session.query(CustomSets).filter( CustomSets.user == user).all(): customs = list( meta.Session.query(CustomSet).filter( sa.and_(CustomSet.user == user, CustomSet.setname == csets.setname, CustomSet.version == csets.active)).all()) orders.extend(customs) for custom in orders: try: #print "Found custom set:",custom.setname ##print "Found active custom set:",custom.setname,custom.version #print "Data:" #print "------------------" #print custom.data #print "Cont1" data = json.loads(u"".join([ x for x in custom.data.split("\n") if not x.strip().startswith("#") ]).encode('utf8')) if type(data) != dict: raise Exception( "Top level must be object, that is, file must start with '{'" ) #print "Cont2" for pointtype in pointtypes: if pointtype in data: out = [] for point in data[pointtype]: #print "val point" if validate_point(point, pointtype, self.log): out.append(point) #print "aft val point" if pointtype == 'airfields': #print "val airf" validate_airfield_space(point, self.log, self.spaces['airspaces']) #print "aft val airf" self.points[pointtype].extend(out) data.pop(pointtype) #print "Cont3" for spacetype in spacestypes: if spacetype in data: out = [] for space in data[spacetype]: if validate_space(space, spacetype, self.log): out.append(space) self.spaces[spacetype].extend(out) data.pop(spacetype) #print "Cont4" if len(data.keys()): for key in data.keys(): self.log.append("Unknown top-level key: %s" % (key, )) #print "Cont5" except Exception, cause: print "Problem parsing custom", traceback.format_exc() self.log.append(traceback.format_exc()) if len(self.log) == 0: #print "About to start bsptreein" for pointtype in pointtypes: bspitems = [] for item in self.points[pointtype]: #print "Adding BspTree item of type: ",pointtype,"item:",item bspitems.append( BspTree.Item( mapper.latlon2merc(mapper.from_str(item['pos']), 13), item)) self.pointslookup[pointtype] = BspTree(bspitems) if bspitems: self.empty = False airspaces = self.spaces.get('airspaces', []) firs = [space for space in airspaces if space['type'] == 'FIR'] regular_airspaces = [ space for space in airspaces if space['type'] != 'FIR' ] self.spaces['airspaces'] = regular_airspaces self.spaces['firs'] = firs if len(self.log) == 0: for spacetype in spacestypes: bbitems = [] for space in self.spaces[spacetype]: poly_coords = [] bb = BoundingBox(1e30, 1e30, -1e30, -1e30) for coord in space['points']: print "Coord:", coord x, y = mapper.latlon2merc(mapper.from_str(coord), zoomlevel) bb.x1 = min(bb.x1, x) bb.x2 = max(bb.x2, x) bb.y1 = min(bb.y1, y) bb.y2 = max(bb.y2, y) poly_coords.append(Vertex(int(x), int(y))) if len(poly_coords) < 3: continue poly = Polygon(vvector(poly_coords)) #print "Item:",space bbitems.append(BBTree.TItem(bb, (poly, space))) self.spaceslookup[spacetype] = BBTree(bbitems, 0.5) if bbitems: self.empty = False self.date = datetime.utcnow()
def test_polygon_intersect_line4(): polya=Polygon(vvector([ Vertex(0,0),Vertex(5,0),Vertex(10,0),Vertex(5,0),Vertex(1,0),Vertex(0,1)])) ls=list(polya.intersect_line(Line(Vertex(-5,0),Vertex(15,0)))) print ls assert ls==[Line(Vertex(0,0),Vertex(10,0))]
def test_polygon_intersect_line15(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(0,10)])) ls=list(polya.intersect_line(Line(Vertex(10,-15),Vertex(10,25)))) print ls assert ls==[Line(Vertex(10,0),Vertex(10,10))]
def test_remove_loops5(): polya=Polygon(vvector([ Vertex(0,0),Vertex(80,0),Vertex(100,0),Vertex(80,0),Vertex(0,2)])) polyb=polya.remove_loops() assert polyb==Polygon(vvector([ Vertex(0,0),Vertex(60,0),Vertex(0,2)]))
def test_merge_straights(): polya=Polygon(vvector([ Vertex(0,0),Vertex(5,0),Vertex(10,0),Vertex(10,10),Vertex(0,10)])) polya.merge_straight_sections() assert polya==Polygon(vvector([ Vertex(0,0),Vertex(10,0),Vertex(10,10),Vertex(0,10)]))
def gen_bsptree_lookup(data): r = dict() lookup_points = ['obstacles', 'airfields', 'sig_points'] for look in lookup_points: items = data.get(look, None) if True: bspitems = [] for item in items: try: bspitems.append( BspTree.Item( mapper.latlon2merc(mapper.from_str(item['pos']), 13), item)) except Exception: print item raise #print "Items for bsptree",items bsp = BspTree(bspitems) #assert len(bsp.getall())==len(items) #after=sorted(set(x['name'] for x in bsp.getall())) #before=sorted(set(x['name'] for x in obsts)) #print after,"\n-------------------\n\n",before #assert after==before #print "same before as after" r[look] = bsp del item del items del bspitems del bsp lookup_spaces = ['airspaces', 'firs'] for look in lookup_spaces: spaces = data.get(look, None) if spaces != None: bbitems = [] zoomlevel = 13 for space in spaces: poly_coords = [] bb = BoundingBox(1e30, 1e30, -1e30, -1e30) for coord in space['points']: x, y = mapper.latlon2merc(mapper.from_str(coord), zoomlevel) bb.x1 = min(bb.x1, x) bb.x2 = max(bb.x2, x) bb.y1 = min(bb.y1, y) bb.y2 = max(bb.y2, y) poly_coords.append(Vertex(int(x), int(y))) if len(set(poly_coords)) < 3: continue print "Poly" poly = Polygon(vvector(poly_coords)) print "polydone" #print "Item:",space bbitems.append(BBTree.TItem(bb, (poly, space))) #if poly.is_inside(Vertex(int(px),int(py))): # insides.append(space) bbt = BBTree(bbitems, 0.5) r[look] = bbt return r
def extract_airfields(filtericao=lambda x:True,purge=True): #print getxml("/AIP/AD/AD 1/ES_AD_1_1_en.pdf") ads=[] p=Parser("/AIP/AD/AD 1/ES_AD_1_1_en.pdf") points=dict() startpage=None for pagenr in xrange(p.get_num_pages()): page=p.parse_page_to_items(pagenr) if page.count("Aerodrome directory"): startpage=pagenr break if startpage==None: raise Exception("Couldn't find aerodrome directory in file") #print "Startpage: %d"%(startpage,) #nochartf=open("nochart.txt","w") for pagenr in xrange(startpage,p.get_num_pages()): row_y=[] page=p.parse_page_to_items(pagenr) allines=[x for x in (page.get_lines(page.get_partially_in_rect(0,0,15,100))) if x.strip()] for item,next in zip(allines,allines[1:]+[""]): #print "item:",item m=re.match(ur"^\s*[A-ZÅÄÖ]{3,}(?:/.*)?\b.*",item) if m: #print "Candidate, next is:",next if re.match(r"^\s*[A-Z]{4}\b.*",next): #print "Matched:",item #print "y1:",item.y1 row_y.append(item.y1) for y1,y2 in zip(row_y,row_y[1:]+[100.0]): #print "Extacting from y-range: %f-%f"%(y1,y2) items=list(page.get_partially_in_rect(0,y1-0.25,5.0,y2+0.25,ysort=True)) if len(items)>=2: #print "Extract items",items ad=dict(name=unicode(items[0].text).strip(), icao=unicode(items[1].text).strip() ) #print "Icao:",ad['icao'] assert re.match(r"[A-Z]{4}",ad['icao']) if not filtericao(ad): continue if len(items)>=3: #print "Coord?:",items[2].text m=re.match(r".*(\d{6}N)\s*(\d{7}E).*",items[2].text) if m: lat,lon=m.groups() ad['pos']=parse_coords(lat,lon) #print "Items3:",items[3:] elev=re.findall(r"(\d{1,5})\s*ft"," ".join(t.text for t in items[3:])) #print "Elev:",elev assert len(elev)==1 ad['elev']=int(elev[0]) ads.append(ad) big_ad=set() for ad in ads: if not ad.has_key('pos'): big_ad.add(ad['icao']) for ad in ads: icao=ad['icao'] if icao in big_ad: if icao in ['ESIB','ESNY','ESCM','ESPE']: continue try: p=Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_6_1_en.pdf"%(icao,icao)) except: p=Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_6-1_en.pdf"%(icao,icao)) ad['aipvacurl']=p.get_url() for pagenr in xrange(p.get_num_pages()): page=p.parse_page_to_items(pagenr) """ for altline in exitlines: m=re.match(r"(\w+)\s+(\d+N)\s*(\d+E.*)",altline) if not m: continue name,lat,lon=m.groups() try: coord=parse_coords(lat,lon) except Exception: continue points.append(dict(name=name,pos=coord)) """ for kind in xrange(2): if kind==0: hits=page.get_by_regex(r"H[Oo][Ll][Dd][Ii][Nn][Gg]") kind="holding point" if kind==1: hits=page.get_by_regex(r"[Ee]ntry.*[Ee]xit.*point") kind="entry/exit point" if len(hits)==0: continue for holdingheading in hits: items=sorted(page.get_partially_in_rect(holdingheading.x1+2.0,holdingheading.y2+0.1,holdingheading.x1+0.5,100), key=lambda x:x.y1) items=[x for x in items if not x.text.startswith(" ")] #print "Holding items:",items for idx,item in enumerate(items): print "Holding item",item y1=item.y1 if idx==len(items)-1: y2=100 else: y2=items[idx+1].y1 items2=[x for x in page.get_partially_in_rect(item.x1+1,y1+0.3,item.x1+40,y2-0.1) if x.x1>=item.x1-0.25 and x.y1>=y1-0.05 and x.y1<y2-0.05] s=(" ".join(page.get_lines(items2))).strip() print "Holding lines:",repr(page.get_lines(items2)) #if s.startswith("ft Left/3"): #Special case for ESOK # s,=re.match("ft Left/3.*?([A-Z]{4,}.*)",s).groups() #m=re.match("ft Left/\d+.*?([A-Z]{4,}.*)",s) #if m: # s,=m.groups() if s.startswith("LjUNG"): #Really strange problem with ESCF s=s[0]+"J"+s[2:] if s.lower().startswith("holding"): sl=s.split(" ",1) if len(sl)>1: s=sl[1] s=s.strip() if kind=="entry/exit point" and s.startswith("HOLDING"): continue #reached HOLDING-part of VAC #Check for other headings #Fixup strange formatting of points in some holding items: (whitespace between coord and 'E') s=re.sub(ur"(\d+)\s*(N)\s*(\d+)\s*(E)",lambda x:"".join(x.groups()),s) m=re.match(r"([A-Z]{2,}).*?(\d+N)\s*(\d+E).*",s) if not m: m=re.match(r".*?(\d+N)\s*(\d+E).*",s) if not m: continue assert m lat,lon=m.groups() #skavsta if icao=="ESKN": if s.startswith(u"Hold north of T"): name="NORTH" elif s.startswith(u"Hold south of B"): name="SOUTH" else: assert 0 #add more specials here else: continue else: name,lat,lon=m.groups() try: coord=parse_coords(lat,lon) except Exception: print "Couldn't parse:",lat,lon continue #print name,lat,lon,mapper.format_lfv(*mapper.from_str(coord)) if name.count("REMARK") or len(name)<=2: print "Suspicious name: ",name #sys.exit(1) continue points[icao+' '+name]=dict(name=icao+' '+name,icao=icao,pos=coord,kind=kind) #for point in points.items(): # print point #sys.exit(1) def fixhex11(s): out=[] for c in s: i=ord(c) if i>=0x20: out.append(c) continue if i in [0x9,0xa,0xd]: out.append(c) continue out.append(' ') return "".join(out) for ad in ads: icao=ad['icao'] if icao in big_ad: #print "Parsing ",icao p=Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_en.pdf"%(icao,icao),loadhook=fixhex11) ad['aiptexturl']=p.get_url() firstpage=p.parse_page_to_items(0) te="\n".join(firstpage.get_all_lines()) #print te coords=re.findall(r"ARP.*(\d{6}N)\s*(\d{7}E)",te) if len(coords)>1: raise Exception("First page of airport info (%s) does not contain exactly ONE set of coordinates"%(icao,)) if len(coords)==0: print "Couldn't find coords for ",icao #print "Coords:",coords ad['pos']=parse_coords(*coords[0]) elev=re.findall(r"Elevation.*?(\d{1,5})\s*ft",te,re.DOTALL) if len(elev)>1: raise Exception("First page of airport info (%s) does not contain exactly ONE elevation in ft"%(icao,)) if len(elev)==0: print "Couldn't find elev for ",icao ad['elev']=int(elev[0]) freqs=[] found=False thrs=[] #uprint("-------------------------------------") for pagenr in xrange(p.get_num_pages()): page=p.parse_page_to_items(pagenr) #uprint("Looking on page %d"%(pagenr,)) if 0: #opening hours are no longer stored in a separate document for any airports. No need to detect which any more (since none are). for item in page.get_by_regex(".*OPERATIONAL HOURS.*"): lines=page.get_lines(page.get_partially_in_rect(0,item.y2+0.1,100,100)) for line in lines: things=["ATS","Fuelling","Operating"] if not line.count("AIP SUP"): continue for thing in things: if line.count(thing): ad['aipsup']=True for item in page.get_by_regex(".*\s*RUNWAY\s*PHYSICAL\s*CHARACTERISTICS\s*.*"): #uprint("Physical char on page") lines=page.get_lines(page.get_partially_in_rect(0,item.y2+0.1,100,100)) seen_end_rwy_text=False for line,nextline in izip(lines,lines[1:]+[None]): #uprint("MAtching: <%s>"%(line,)) if re.match(ur"AD\s+2.13",line): break if line.count("Slope of"): break if line.lower().count("end rwy:"): seen_end_rwy_text=True if line.lower().count("bgn rwy:"): seen_end_rwy_text=True m=re.match(ur".*(\d{6}\.\d+)[\s\(\)\*]*(N).*",line) if not m:continue m2=re.match(ur".*(\d{6,7}\.\d+)\s*[\s\(\)\*]*(E).*",nextline) if not m2:continue latd,n=m.groups() lond,e=m2.groups() assert n=="N" assert e=="E" lat=latd+n lon=lond+e rwytxts=page.get_lines(page.get_partially_in_rect(0,line.y1+0.05,12,nextline.y2-0.05)) uprint("Rwytxts:",rwytxts) rwy=None for rwytxt in rwytxts: #uprint("lat,lon:%s,%s"%(lat,lon)) #uprint("rwytext:",rwytxt) m=re.match(ur"\s*(\d{2}[LRCM]?)\b.*",rwytxt) if m: assert rwy==None rwy=m.groups()[0] if rwy==None and seen_end_rwy_text: continue print "Cur airport:",icao already=False assert rwy!=None seen_end_rwy_text=False for thr in thrs: if thr['thr']==rwy: raise Exception("Same runway twice on airfield:"+icao) thrs.append(dict(pos=mapper.parse_coords(lat,lon),thr=rwy)) assert len(thrs)>=2 for pagenr in xrange(0,p.get_num_pages()): page=p.parse_page_to_items(pagenr) matches=page.get_by_regex(r".*ATS\s+COMMUNICATION\s+FACILITIES.*") #print "Matches of ATS COMMUNICATION FACILITIES on page %d: %s"%(pagenr,matches) if len(matches)>0: commitem=matches[0] curname=None callsign=page.get_by_regex_in_rect(ur"Call\s*sign",0,commitem.y1,100,commitem.y2+8)[0] for idx,item in enumerate(page.get_lines(page.get_partially_in_rect(callsign.x1-0.5,commitem.y1,100,100),fudge=0.3,order_fudge=15)): if item.strip()=="": curname=None if re.match(".*RADIO\s+NAVIGATION\s+AND\s+LANDING\s+AIDS.*",item): break #print "Matching:",item m=re.match(r"(.*?)\s*(\d{3}\.\d{1,3})\s*MHz.*",item) #print "MHZ-match:",m if not m: continue #print "MHZ-match:",m.groups() who,sfreq=m.groups() freq=float(sfreq) if abs(freq-121.5)<1e-4: if who.strip(): curname=who continue #Ignore emergency frequency, it is understood if not who.strip(): if curname==None: continue else: curname=who freqs.append((curname.strip().rstrip("/"),freq)) for pagenr in xrange(0,p.get_num_pages()): page=p.parse_page_to_items(pagenr) matches=page.get_by_regex(r".*ATS\s*AIRSPACE.*") #print "Matches of ATS_AIRSPACE on page %d: %s"%(pagenr,matches) if len(matches)>0: heading=matches[0] desigitem,=page.get_by_regex("Designation and lateral limits") vertitem,=page.get_by_regex("Vertical limits") airspaceclass,=page.get_by_regex("Airspace classification") lastname=None subspacelines=dict() subspacealts=dict() for idx,item in enumerate(page.get_lines(page.get_partially_in_rect(desigitem.x2+1,desigitem.y1,100,vertitem.y1-1))): if item.count("ATS airspace not established"): assert idx==0 break if item.strip()=="": continue m=re.match(r"(.*?)(\d{6}N\s+.*)",item) if m: name,coords=m.groups() name=name.strip() else: name=item.strip() coords=None if name: lastname=name if coords: subspacelines.setdefault(lastname,[]).append(coords) assert lastname lastname=None #print "Spaces:",subspacelines #print "ICAO",ad['icao'] #altlines=page.get_lines(page.get_partially_in_rect(vertitem.x2+1,vertitem.y1,100,airspaceclass.y1-0.2)) #print "Altlines:",altlines subspacealts=dict() subspacekeys=subspacelines.keys() allaltlines=" ".join(page.get_lines(page.get_partially_in_rect(vertitem.x1+0.5,vertitem.y1+0.5,100,airspaceclass.y1-0.2))) single_vertlim=False totalts=list(mapper.parse_all_alts(allaltlines)) #print "totalts:",totalts if len(totalts)==2: single_vertlim=True for subspacename in subspacekeys: ceil=None floor=None subnames=[subspacename] if subspacename.split(" ")[-1].strip() in ["TIA","TIZ","CTR","CTR/TIZ"]: subnames.append(subspacename.split(" ")[-1].strip()) #print "Parsing alts for ",subspacename,subnames try: for nametry in subnames: if single_vertlim: #there's only one subspace, parse all of vertical limits field for this single one. items=[vertitem] else: items=page.get_by_regex_in_rect(nametry,vertitem.x2+1,vertitem.y1,100,airspaceclass.y1-0.2) for item in items: alts=[] for line in page.get_lines(page.get_partially_in_rect(item.x1+0.5,item.y1+0.5,100,airspaceclass.y1-0.2)): #print "Parsing:",line line=line.replace(nametry,"").lower().strip() parsed=list(mapper.parse_all_alts(line)) if len(parsed): alts.append(mapper.altformat(*parsed[0])) if len(alts)==2: break if alts: #print "alts:",alts ceil,floor=alts raise StopIteration except StopIteration: pass assert ceil and floor subspacealts[subspacename]=dict(ceil=ceil,floor=floor) spaces=[] for spacename in subspacelines.keys(): altspacename=spacename #print "Altspacename: %s, subspacesalts: %s"%(altspacename,subspacealts) space=dict( name=spacename, ceil=subspacealts[altspacename]['ceil'], floor=subspacealts[altspacename]['floor'], points=parse_coord_str(" ".join(subspacelines[spacename])), freqs=list(set(freqs)) ) if True: vs=[] for p in space['points']: x,y=mapper.latlon2merc(mapper.from_str(p),13) vs.append(Vertex(int(x),int(y))) p=Polygon(vvector(vs)) if p.calc_area()<=30*30: pass#print space pass#print "Area:",p.calc_area() assert p.calc_area()>30*30 #print "Area: %f"%(p.calc_area(),) spaces.append(space) #print space ad['spaces']=spaces found=True if found: break assert found ad['runways']=rwy_constructor.get_rwys(thrs) #Now find any ATS-airspace chartblobnames=[] for ad in ads: icao=ad['icao'] if icao in big_ad: parse_landing_chart.help_plc(ad,"/AIP/AD/AD 2/%s/ES_AD_2_%s_2-1_en.pdf"%(icao,icao), icao,ad['pos'],"se",variant="") parse_landing_chart.help_plc(ad,"/AIP/AD/AD 2/%s/ES_AD_2_%s_6-1_en.pdf"%(icao,icao), icao,ad['pos'],"se",variant="vac") parse_landing_chart.help_plc(ad,"/AIP/AD/AD 2/%s/ES_AD_2_%s_2-3_en.pdf"%(icao,icao), icao,ad['pos'],"se",variant="parking") #aip_text_documents.help_parse_doc(ad,"/AIP/AD/AD 2/%s/ES_AD_2_%s_6_1_en.pdf"%(icao,icao), # icao,"se",title="General Information",category="general") aip_text_documents.help_parse_doc(ad,"/AIP/AD/AD 2/%s/ES_AD_2_%s_en.pdf"%(icao,icao), icao,"se",title="General Information",category="general") #if purge: # parse_landing_chart.purge_old(chartblobnames,country="se") #sys.exit(1) for extra in extra_airfields.extra_airfields: if filtericao(extra): ads.append(extra) print print for k,v in sorted(points.items()): print k,v,mapper.format_lfv(*mapper.from_str(v['pos'])) #print "Num points:",len(points) origads=list(ads) for flygkartan_id,name,lat,lon,dummy in csv.reader(open("fplan/extract/flygkartan.csv"),delimiter=";"): found=None lat=float(lat) lon=float(lon) if type(name)==str: name=unicode(name,'utf8') mercf=mapper.latlon2merc((lat,lon),13) for a in origads: merca=mapper.latlon2merc(mapper.from_str(a['pos']),13) dist=math.sqrt((merca[0]-mercf[0])**2+(merca[1]-mercf[1])**2) if dist<120: found=a break if found: found['flygkartan_id']=flygkartan_id else: d=dict( icao='ZZZZ', name=name, pos=mapper.to_str((lat,lon)), elev=int(get_terrain_elev((lat,lon))), flygkartan_id=flygkartan_id) if filtericao(d): ads.append(d) minor_ad_charts=extra_airfields.minor_ad_charts for ad in ads: if ad['name'].count(u"Långtora"): ad['pos']=mapper.to_str(mapper.from_aviation_format("5944.83N01708.20E")) if ad['name'] in minor_ad_charts: charturl=minor_ad_charts[ad['name']] arp=ad['pos'] if 'icao' in ad and ad['icao'].upper()!='ZZZZ': icao=ad['icao'].upper() else: icao=ad['fake_icao'] parse_landing_chart.help_plc(ad,charturl,icao,arp,country='raw',variant="landing") """ assert icao!=None lc=parse_landing_chart.parse_landing_chart( charturl, icao=icao, arppos=arp,country="raw") assert lc if lc: ad['adcharturl']=lc['url'] ad['adchart']=lc """ #print ads for ad in ads: print "%s: %s - %s (%s ft) (%s)"%(ad['icao'],ad['name'],ad['pos'],ad['elev'],ad.get('flygkartan_id','inte i flygkartan')) for space in ad.get('spaces',[]): for freq in space.get('freqs',[]): print " ",freq #if 'spaces' in ad: # print " spaces: %s"%(ad['spaces'],) #if 'aiptext' in ad: # print "Aip texts:",ad['aiptext'] #else: # print "No aiptext" print "Points:" for point in sorted(points.values(),key=lambda x:x['name']): print point f=codecs.open("extract_airfields.regress.txt","w",'utf8') for ad in ads: r=repr(ad) d=md5.md5(r).hexdigest() f.write("%s - %s - %s\n"%(ad['icao'],ad['name'],d)) f.close() f=codecs.open("extract_airfields.regress-details.txt","w",'utf8') for ad in ads: r=repr(ad) f.write(u"%s - %s - %s\n"%(ad['icao'],ad['name'],r)) f.close() return ads,points.values()
def test_polygon_intersect_line23(): polya=Polygon(vvector([ Vertex(0,0),Vertex(10000000,0),Vertex(10000000,10000000),Vertex(0,10000000)])) ls=list(polya.intersect_line(Line(Vertex(-5000000,5000000),Vertex(15000000,5000000)))) print ls assert ls==[Line(Vertex(0,5000000),Vertex(10000000,5000000))]
def extract_airfields(filtericao=lambda x: True, purge=True): # print getxml("/AIP/AD/AD 1/ES_AD_1_1_en.pdf") ads = [] p = Parser("/AIP/AD/AD 1/ES_AD_1_1_en.pdf") points = dict() startpage = None for pagenr in xrange(p.get_num_pages()): page = p.parse_page_to_items(pagenr) if page.count("Aerodrome directory"): startpage = pagenr break if startpage == None: raise Exception("Couldn't find aerodrome directory in file") # print "Startpage: %d"%(startpage,) # nochartf=open("nochart.txt","w") for pagenr in xrange(startpage, p.get_num_pages()): row_y = [] page = p.parse_page_to_items(pagenr) allines = [x for x in (page.get_lines(page.get_partially_in_rect(0, 0, 15, 100))) if x.strip()] for item, next in zip(allines, allines[1:] + [""]): # print "item:",item m = re.match(ur"^\s*[A-ZÅÄÖ]{3,}(?:/.*)?\b.*", item) if m: # print "Candidate, next is:",next if re.match(r"^\s*[A-Z]{4}\b.*", next): # print "Matched:",item # print "y1:",item.y1 row_y.append(item.y1) for y1, y2 in zip(row_y, row_y[1:] + [100.0]): # print "Extacting from y-range: %f-%f"%(y1,y2) items = list(page.get_partially_in_rect(0, y1 - 0.25, 5.0, y2 + 0.25, ysort=True)) if len(items) >= 2: # print "Extract items",items ad = dict(name=unicode(items[0].text).strip(), icao=unicode(items[1].text).strip()) # print "Icao:",ad['icao'] assert re.match(r"[A-Z]{4}", ad["icao"]) if not filtericao(ad): continue if len(items) >= 3: # print "Coord?:",items[2].text m = re.match(r".*(\d{6}N)\s*(\d{7}E).*", items[2].text) if m: lat, lon = m.groups() ad["pos"] = parse_coords(lat, lon) # print "Items3:",items[3:] elev = re.findall(r"(\d{1,5})\s*ft", " ".join(t.text for t in items[3:])) # print "Elev:",elev assert len(elev) == 1 ad["elev"] = int(elev[0]) ads.append(ad) big_ad = set() for ad in ads: if not ad.has_key("pos"): big_ad.add(ad["icao"]) for ad in ads: icao = ad["icao"] if icao in big_ad: if icao in ["ESIB", "ESNY", "ESCM", "ESPE"]: continue try: p = Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_6_1_en.pdf" % (icao, icao)) except: p = Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_6-1_en.pdf" % (icao, icao)) ad["aipvacurl"] = p.get_url() for pagenr in xrange(p.get_num_pages()): page = p.parse_page_to_items(pagenr) """ for altline in exitlines: m=re.match(r"(\w+)\s+(\d+N)\s*(\d+E.*)",altline) if not m: continue name,lat,lon=m.groups() try: coord=parse_coords(lat,lon) except Exception: continue points.append(dict(name=name,pos=coord)) """ for kind in xrange(2): if kind == 0: hits = page.get_by_regex(r"H[Oo][Ll][Dd][Ii][Nn][Gg]") kind = "holding point" if kind == 1: hits = page.get_by_regex(r"[Ee]ntry.*[Ee]xit.*point") kind = "entry/exit point" if len(hits) == 0: continue for holdingheading in hits: items = sorted( page.get_partially_in_rect( holdingheading.x1 + 2.0, holdingheading.y2 + 0.1, holdingheading.x1 + 0.5, 100 ), key=lambda x: x.y1, ) items = [x for x in items if not x.text.startswith(" ")] # print "Holding items:",items for idx, item in enumerate(items): print "Holding item", item y1 = item.y1 if idx == len(items) - 1: y2 = 100 else: y2 = items[idx + 1].y1 items2 = [ x for x in page.get_partially_in_rect(item.x1 + 1, y1 + 0.3, item.x1 + 40, y2 - 0.1) if x.x1 >= item.x1 - 0.25 and x.y1 >= y1 - 0.05 and x.y1 < y2 - 0.05 ] s = (" ".join(page.get_lines(items2))).strip() print "Holding lines:", repr(page.get_lines(items2)) # if s.startswith("ft Left/3"): #Special case for ESOK # s,=re.match("ft Left/3.*?([A-Z]{4,}.*)",s).groups() # m=re.match("ft Left/\d+.*?([A-Z]{4,}.*)",s) # if m: # s,=m.groups() if s.startswith("LjUNG"): # Really strange problem with ESCF s = s[0] + "J" + s[2:] if s.lower().startswith("holding"): sl = s.split(" ", 1) if len(sl) > 1: s = sl[1] s = s.strip() if kind == "entry/exit point" and s.startswith("HOLDING"): continue # reached HOLDING-part of VAC # Check for other headings # Fixup strange formatting of points in some holding items: (whitespace between coord and 'E') s = re.sub(ur"(\d+)\s*(N)\s*(\d+)\s*(E)", lambda x: "".join(x.groups()), s) m = re.match(r"([A-Z]{2,}).*?(\d+N)\s*(\d+E).*", s) if not m: m = re.match(r".*?(\d+N)\s*(\d+E).*", s) if not m: continue assert m lat, lon = m.groups() # skavsta if icao == "ESKN": if s.startswith(u"Hold north of T"): name = "NORTH" elif s.startswith(u"Hold south of B"): name = "SOUTH" else: assert 0 # add more specials here else: continue else: name, lat, lon = m.groups() try: coord = parse_coords(lat, lon) except Exception: print "Couldn't parse:", lat, lon continue # print name,lat,lon,mapper.format_lfv(*mapper.from_str(coord)) if name.count("REMARK") or len(name) <= 2: print "Suspicious name: ", name # sys.exit(1) continue points[icao + " " + name] = dict(name=icao + " " + name, icao=icao, pos=coord, kind=kind) # for point in points.items(): # print point # sys.exit(1) def fixhex11(s): out = [] for c in s: i = ord(c) if i >= 0x20: out.append(c) continue if i in [0x9, 0xA, 0xD]: out.append(c) continue out.append(" ") return "".join(out) for ad in ads: icao = ad["icao"] if icao in big_ad: # print "Parsing ",icao p = Parser("/AIP/AD/AD 2/%s/ES_AD_2_%s_en.pdf" % (icao, icao), loadhook=fixhex11) ad["aiptexturl"] = p.get_url() firstpage = p.parse_page_to_items(0) te = "\n".join(firstpage.get_all_lines()) # print te coords = re.findall(r"ARP.*(\d{6}N)\s*(\d{7}E)", te) if len(coords) > 1: raise Exception( "First page of airport info (%s) does not contain exactly ONE set of coordinates" % (icao,) ) if len(coords) == 0: print "Couldn't find coords for ", icao # print "Coords:",coords ad["pos"] = parse_coords(*coords[0]) elev = re.findall(r"Elevation.*?(\d{1,5})\s*ft", te, re.DOTALL) if len(elev) > 1: raise Exception( "First page of airport info (%s) does not contain exactly ONE elevation in ft" % (icao,) ) if len(elev) == 0: print "Couldn't find elev for ", icao ad["elev"] = int(elev[0]) freqs = [] found = False thrs = [] # uprint("-------------------------------------") for pagenr in xrange(p.get_num_pages()): page = p.parse_page_to_items(pagenr) # uprint("Looking on page %d"%(pagenr,)) if ( 0 ): # opening hours are no longer stored in a separate document for any airports. No need to detect which any more (since none are). for item in page.get_by_regex(".*OPERATIONAL HOURS.*"): lines = page.get_lines(page.get_partially_in_rect(0, item.y2 + 0.1, 100, 100)) for line in lines: things = ["ATS", "Fuelling", "Operating"] if not line.count("AIP SUP"): continue for thing in things: if line.count(thing): ad["aipsup"] = True for item in page.get_by_regex(".*\s*RUNWAY\s*PHYSICAL\s*CHARACTERISTICS\s*.*"): # uprint("Physical char on page") lines = page.get_lines(page.get_partially_in_rect(0, item.y2 + 0.1, 100, 100)) seen_end_rwy_text = False for line, nextline in izip(lines, lines[1:] + [None]): # uprint("MAtching: <%s>"%(line,)) if re.match(ur"AD\s+2.13", line): break if line.count("Slope of"): break if line.lower().count("end rwy:"): seen_end_rwy_text = True if line.lower().count("bgn rwy:"): seen_end_rwy_text = True m = re.match(ur".*(\d{6}\.\d+)[\s\(\)\*]*(N).*", line) if not m: continue m2 = re.match(ur".*(\d{6,7}\.\d+)\s*[\s\(\)\*]*(E).*", nextline) if not m2: continue latd, n = m.groups() lond, e = m2.groups() assert n == "N" assert e == "E" lat = latd + n lon = lond + e rwytxts = page.get_lines(page.get_partially_in_rect(0, line.y1 + 0.05, 12, nextline.y2 - 0.05)) uprint("Rwytxts:", rwytxts) rwy = None for rwytxt in rwytxts: # uprint("lat,lon:%s,%s"%(lat,lon)) # uprint("rwytext:",rwytxt) m = re.match(ur"\s*(\d{2}[LRCM]?)\b.*", rwytxt) if m: assert rwy == None rwy = m.groups()[0] if rwy == None and seen_end_rwy_text: continue print "Cur airport:", icao already = False assert rwy != None seen_end_rwy_text = False for thr in thrs: if thr["thr"] == rwy: raise Exception("Same runway twice on airfield:" + icao) thrs.append(dict(pos=mapper.parse_coords(lat, lon), thr=rwy)) assert len(thrs) >= 2 for pagenr in xrange(0, p.get_num_pages()): page = p.parse_page_to_items(pagenr) matches = page.get_by_regex(r".*ATS\s+COMMUNICATION\s+FACILITIES.*") # print "Matches of ATS COMMUNICATION FACILITIES on page %d: %s"%(pagenr,matches) if len(matches) > 0: commitem = matches[0] curname = None callsign = page.get_by_regex_in_rect(ur"Call\s*sign", 0, commitem.y1, 100, commitem.y2 + 8)[0] for idx, item in enumerate( page.get_lines( page.get_partially_in_rect(callsign.x1 - 0.5, commitem.y1, 100, 100), fudge=0.3, order_fudge=15, ) ): if item.strip() == "": curname = None if re.match(".*RADIO\s+NAVIGATION\s+AND\s+LANDING\s+AIDS.*", item): break # print "Matching:",item m = re.match(r"(.*?)\s*(\d{3}\.\d{1,3})\s*MHz.*", item) # print "MHZ-match:",m if not m: continue # print "MHZ-match:",m.groups() who, sfreq = m.groups() freq = float(sfreq) if abs(freq - 121.5) < 1e-4: if who.strip(): curname = who continue # Ignore emergency frequency, it is understood if not who.strip(): if curname == None: continue else: curname = who freqs.append((curname.strip().rstrip("/"), freq)) for pagenr in xrange(0, p.get_num_pages()): page = p.parse_page_to_items(pagenr) matches = page.get_by_regex(r".*ATS\s*AIRSPACE.*") # print "Matches of ATS_AIRSPACE on page %d: %s"%(pagenr,matches) if len(matches) > 0: heading = matches[0] desigitem, = page.get_by_regex("Designation and lateral limits") vertitem, = page.get_by_regex("Vertical limits") airspaceclass, = page.get_by_regex("Airspace classification") lastname = None subspacelines = dict() subspacealts = dict() for idx, item in enumerate( page.get_lines(page.get_partially_in_rect(desigitem.x2 + 1, desigitem.y1, 100, vertitem.y1 - 1)) ): if item.count("ATS airspace not established"): assert idx == 0 break if item.strip() == "": continue m = re.match(r"(.*?)(\d{6}N\s+.*)", item) if m: name, coords = m.groups() name = name.strip() else: name = item.strip() coords = None if name: lastname = name if coords: subspacelines.setdefault(lastname, []).append(coords) assert lastname lastname = None # print "Spaces:",subspacelines # print "ICAO",ad['icao'] # altlines=page.get_lines(page.get_partially_in_rect(vertitem.x2+1,vertitem.y1,100,airspaceclass.y1-0.2)) # print "Altlines:",altlines subspacealts = dict() subspacekeys = subspacelines.keys() allaltlines = " ".join( page.get_lines( page.get_partially_in_rect( vertitem.x1 + 0.5, vertitem.y1 + 0.5, 100, airspaceclass.y1 - 0.2 ) ) ) single_vertlim = False totalts = list(mapper.parse_all_alts(allaltlines)) # print "totalts:",totalts if len(totalts) == 2: single_vertlim = True for subspacename in subspacekeys: ceil = None floor = None subnames = [subspacename] if subspacename.split(" ")[-1].strip() in ["TIA", "TIZ", "CTR", "CTR/TIZ"]: subnames.append(subspacename.split(" ")[-1].strip()) # print "Parsing alts for ",subspacename,subnames try: for nametry in subnames: if ( single_vertlim ): # there's only one subspace, parse all of vertical limits field for this single one. items = [vertitem] else: items = page.get_by_regex_in_rect( nametry, vertitem.x2 + 1, vertitem.y1, 100, airspaceclass.y1 - 0.2 ) for item in items: alts = [] for line in page.get_lines( page.get_partially_in_rect( item.x1 + 0.5, item.y1 + 0.5, 100, airspaceclass.y1 - 0.2 ) ): # print "Parsing:",line line = line.replace(nametry, "").lower().strip() parsed = list(mapper.parse_all_alts(line)) if len(parsed): alts.append(mapper.altformat(*parsed[0])) if len(alts) == 2: break if alts: # print "alts:",alts ceil, floor = alts raise StopIteration except StopIteration: pass assert ceil and floor subspacealts[subspacename] = dict(ceil=ceil, floor=floor) spaces = [] for spacename in subspacelines.keys(): altspacename = spacename # print "Altspacename: %s, subspacesalts: %s"%(altspacename,subspacealts) space = dict( name=spacename, ceil=subspacealts[altspacename]["ceil"], floor=subspacealts[altspacename]["floor"], points=parse_coord_str(" ".join(subspacelines[spacename])), freqs=list(set(freqs)), ) if True: vs = [] for p in space["points"]: x, y = mapper.latlon2merc(mapper.from_str(p), 13) vs.append(Vertex(int(x), int(y))) p = Polygon(vvector(vs)) if p.calc_area() <= 30 * 30: pass # print space pass # print "Area:",p.calc_area() assert p.calc_area() > 30 * 30 # print "Area: %f"%(p.calc_area(),) spaces.append(space) # print space ad["spaces"] = spaces found = True if found: break assert found ad["runways"] = rwy_constructor.get_rwys(thrs)