def read_apt_dat_gz_file(min_lon: float, min_lat: float, max_lon: float, max_lat: float, read_water_runways: bool = False) -> List[Airport]: apt_dat_gz_file = os.path.join(utilities.get_fg_root(), 'Airports', 'apt.dat.gz') start_time = time.time() airports = list() total_airports = 0 with gzip.open(apt_dat_gz_file, 'rt', encoding="latin-1") as f: my_airport = None boundary = None current_boundary_nodes = list() in_boundary = False for line in f: parts = line.split() if not parts: continue if in_boundary: if parts[0] not in ['111', '112', '113', '114', '115', '116']: in_boundary = False else: current_boundary_nodes.append((float(parts[2]), float(parts[1]))) if parts[0] in ['113', '114']: # closed loop boundary.append_nodes_list(current_boundary_nodes) current_boundary_nodes = list() if parts[0] in ['1', '16', '17', '99']: # first actually append the previously read airport data to the collection if within bounds if (my_airport is not None) and (my_airport.within_boundary(min_lon, min_lat, max_lon, max_lat)): airports.append(my_airport) # and then create a new empty airport if not parts[0] == '99': my_airport = Airport(parts[4], parts[5], int(parts[0])) total_airports += 1 elif parts[0] == '100': my_runway = LandRunway(float(parts[1]), co.Vec2d(float(parts[10]), float(parts[9])), co.Vec2d(float(parts[19]), float(parts[18]))) my_airport.append_runway(my_runway) elif parts[0] == '101': if read_water_runways: my_runway = WaterRunway(float(parts[1]), co.Vec2d(float(parts[5]), float(parts[4])), co.Vec2d(float(parts[8]), float(parts[7]))) my_airport.append_runway(my_runway) elif parts[0] == '102': my_helipad = Helipad(float(parts[5]), float(parts[6]), co.Vec2d(float(parts[3]), float(parts[2])), float(parts[4])) my_airport.append_runway(my_helipad) elif parts[0] == '110': # Pavement name = 'no name' if len(parts) == 5: name = parts[4] boundary = Boundary(name) in_boundary = True my_airport.append_pavement(boundary) elif parts[0] == '130': # Airport boundary header boundary = Boundary(parts[1]) in_boundary = True my_airport.append_airport_boundary(boundary) logging.info("Read %d airports, %d having runways/helipads within the boundary", total_airports, len(airports)) utilities.time_logging("Execution time", start_time) return airports
def get_extent_local( transformer: co.Transformation) -> typing.Tuple[co.Vec2d, co.Vec2d]: cmin = co.Vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH) cmax = co.Vec2d(BOUNDARY_EAST, BOUNDARY_NORTH) logging.info("min/max " + str(cmin) + " " + str(cmax)) lmin = co.Vec2d(transformer.to_local((cmin.x, cmin.y))) lmax = co.Vec2d(transformer.to_local((cmax.x, cmax.y))) return lmin, lmax
def _write_pier_area(self, obj: ac3d.Object, offset: co.Vec2d) -> None: """Writes a Pier mapped as an area""" if len(self.nodes) < 3: logging.debug( 'ERROR: platform with osm_id=%d cannot created due to less then 3 nodes', self.osm_id) return linear_ring = shg.LinearRing(self.nodes) # TODO shg.LinearRing().is_ccw o = obj.next_node_index() if linear_ring.is_ccw: logging.info('CounterClockWise') else: # normalize to CCW logging.info("Clockwise") self.nodes = self.nodes[::-1] # top ring e = self.elevation + 1 for p in self.nodes: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) top_nodes = np.arange(len(self.nodes)) self.segment_len = np.array([0] + [ co.Vec2d(coord).distance_to(co.Vec2d(linear_ring.coords[i])) for i, coord in enumerate(linear_ring.coords[1:]) ]) rd_len = len(linear_ring.coords) self.dist = np.zeros((rd_len)) for i in range(1, rd_len): self.dist[i] = self.dist[i - 1] + self.segment_len[i] face = [] x = 0. # reversed(list(enumerate(a))) # Top Face for i, n in enumerate(top_nodes): face.append((n + o, x, 0.5)) obj.face(face) # Build bottom ring e = self.elevation - 5 for p in self.nodes: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) # Build Sides for i, n in enumerate(top_nodes[1:]): sideface = list() sideface.append((n + o + rd_len - 1, x, 0.5)) sideface.append((n + o + rd_len, x, 0.5)) sideface.append((n + o, x, 0.5)) sideface.append((n + o - 1, x, 0.5)) obj.face(sideface)
def process_details(coords_transform: co.Transformation, lit_areas: Optional[List[shg.Polygon]], fg_elev: utilities.FGElev, file_lock: mp.Lock = None) -> None: stats = utilities.Stats() lmin, lmax = parameters.get_extent_local(coords_transform) clusters = ClusterContainer(lmin, lmax) # piers the_piers = piers.process_osm_piers(coords_transform) logging.info("number of piers: %i", len(the_piers)) for pier in the_piers: clusters.append(pier.anchor, pier, stats) for pier in the_piers: pier.calc_elevation(fg_elev) # platforms the_platforms = platforms.process_osm_platform(coords_transform) logging.info("number of platforms: %i", len(the_platforms)) for platform in the_platforms: clusters.append(platform.anchor, platform, stats) # -- initialize STGManager path_to_output = parameters.get_output_path() stg_manager = stg_io2.STGManager(path_to_output, stg_io2.SceneryType.details, OUR_MAGIC, parameters.PREFIX) for cl in clusters: if cl.objects: cluster_center_global = co.Vec2d( coords_transform.to_global(cl.center)) ac_file_name = "%sd%i%i.ac" % (parameters.PREFIX, cl.grid_index.ix, cl.grid_index.iy) ac = ac3d.File(stats=stats) obj = ac.new_object('details', 'Textures/Terrain/asphalt.png', default_mat_idx=mat.Material.unlit.value) for detail in cl.objects[:]: if isinstance(detail, piers.Pier): detail.write(obj, cl.center) else: detail.write(fg_elev, obj, cl.center) path = stg_manager.add_object_static( ac_file_name, cluster_center_global, 0, 0, parameters.get_cluster_dimension_radius()) file_name = os.path.join(path, ac_file_name) f = open(file_name, 'w') f.write(str(ac)) f.close() piers.write_boats(stg_manager, the_piers, coords_transform) # -- write stg stg_manager.write(file_lock) # trigger processing of pylon related details _process_pylon_details(coords_transform, lit_areas, fg_elev, stg_manager, lmin, lmax, file_lock)
def _write_area(self, fg_elev: utilities.FGElev, obj: ac3d.Object, offset: co.Vec2d) -> None: """Writes a platform mapped as an area""" if len(self.nodes) < 3: logging.debug('ERROR: platform with osm_id=%d cannot created due to less then 3 nodes', self.osm_id) return linear_ring = shg.LinearRing(self.nodes) o = obj.next_node_index() if linear_ring.is_ccw: logging.debug('Anti-Clockwise') else: logging.debug("Clockwise") self.nodes = self.nodes[::-1] for p in self.nodes: e = fg_elev.probe_elev((p[0], p[1])) + 1 obj.node(-p[1] + offset.y, e, -p[0] + offset.x) top_nodes = np.arange(len(self.nodes)) self.segment_len = np.array([0] + [co.Vec2d(coord).distance_to(co.Vec2d(self.line_string.coords[i])) for i, coord in enumerate(self.line_string.coords[1:])]) rd_len = len(self.line_string.coords) self.dist = np.zeros((rd_len)) for i in range(1, rd_len): self.dist[i] = self.dist[i - 1] + self.segment_len[i] face = [] x = 0. # Top Face for i, n in enumerate(top_nodes): face.append((n + o, x, 0.5)) obj.face(face) # Build bottom ring for p in self.nodes: e = fg_elev.probe_elev((p[0], p[1])) - 1 obj.node(-p[1] + offset.y, e, -p[0] + offset.x) # Build Sides for i, n in enumerate(top_nodes[1:]): sideface = list() sideface.append((n + o + rd_len - 1, x, 0.5)) sideface.append((n + o + rd_len, x, 0.5)) sideface.append((n + o, x, 0.5)) sideface.append((n + o - 1, x, 0.5)) obj.face(sideface)
def __init__(self, transform, osm_id, tags, refs, nodes_dict): self.osm_id = osm_id self.tags = tags self.refs = refs self.typ = 0 self.nodes = [] self.elevation = 0 self.osm_nodes = list() for r in refs: # safe way instead of [nodes_dict[r] for r in refs] if ref would be missing if r in nodes_dict: self.osm_nodes.append(nodes_dict[r]) self.nodes = np.array( [transform.to_local((n.lon, n.lat)) for n in self.osm_nodes]) self.anchor = co.Vec2d(self.nodes[0])
def __init__(self, transform, osm_id, tags, refs, nodes_dict): self.osm_id = osm_id self.tags = tags self.refs = refs self.typ = 0 self.nodes = [] self.osm_nodes = list() for r in refs: # safe way instead of [nodes_dict[r] for r in refs] if ref would be missing if r in nodes_dict: self.osm_nodes.append(nodes_dict[r]) self.nodes = np.array([transform.to_local((n.lon, n.lat)) for n in self.osm_nodes]) self.is_area = False if s.K_AREA in tags and tags[s.K_AREA] == s.V_YES and len(self.nodes) > 2: self.is_area = True self.line_string = shg.LineString(self.nodes) self.anchor = co.Vec2d(self.nodes[0])
def _write_model(length, stg_manager: stg_io2.STGManager, pos_global, direction, my_elev) -> None: if length < 20: models = [('Models/Maritime/Civilian/wooden_boat.ac', 120), ('Models/Maritime/Civilian/wooden_blue_boat.ac', 120), ('Models/Maritime/Civilian/wooden_green_boat.ac', 120)] choice = randint(0, len(models) - 1) model = models[choice] elif length < 70: models = [('Models/Maritime/Civilian/small-red-yacht.ac', 180), ('Models/Maritime/Civilian/small-black-yacht.ac', 180), ('Models/Maritime/Civilian/small-clear-yacht.ac', 180), ('Models/Maritime/Civilian/wide_black_yacht.ac', 180), ('Models/Maritime/Civilian/wide_red_yacht.ac', 180), ('Models/Maritime/Civilian/wide_clear_yacht.ac', 180), ('Models/Maritime/Civilian/blue-sailing-boat-20m.ac', 180), ('Models/Maritime/Civilian/red-sailing-boat.ac', 180), ('Models/Maritime/Civilian/red-sailing-boat-11m.ac', 180), ('Models/Maritime/Civilian/red-sailing-boat-20m.ac', 180)] choice = randint(0, len(models) - 1) model = models[choice] elif length < 250: models = [('Models/Maritime/Civilian/MediumFerry.xml', 10)] choice = randint(0, len(models) - 1) model = models[choice] elif length < 400: models = [('Models/Maritime/Civilian/LargeTrawler.xml', 10), ('Models/Maritime/Civilian/LargeFerry.xml', 100), ('Models/Maritime/Civilian/barge.xml', 80)] choice = randint(0, len(models) - 1) model = models[choice] else: models = [('Models/Maritime/Civilian/SimpleFreighter.ac', 20), ('Models/Maritime/Civilian/FerryBoat1.ac', 70)] choice = randint(0, len(models) - 1) model = models[choice] stg_manager.add_object_shared(model[0], co.Vec2d(pos_global), my_elev, direction + model[1])
def get_center_global(): cmin = co.Vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH) cmax = co.Vec2d(BOUNDARY_EAST, BOUNDARY_NORTH) return (cmin + cmax) * 0.5
def _write_pier_line(self, obj, offset: co.Vec2d): """Writes a Pier as a area which only is mapped as a line.""" line_string = shg.LineString(self.nodes) o = obj.next_node_index() left = line_string.parallel_offset(1, 'left', resolution=8, join_style=1, mitre_limit=10.0) right = line_string.parallel_offset(1, 'right', resolution=8, join_style=1, mitre_limit=10.0) if not isinstance(left, shg.LineString) or not isinstance( right, shg.LineString): logging.debug( "ERROR: pier with osm_id=%d cannot be created due to geometry constraints", self.osm_id) return idx_left = obj.next_node_index() e = self.elevation + 1 for p in left.coords: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) idx_right = obj.next_node_index() for p in right.coords: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) nodes_l = np.arange(len(left.coords)) nodes_r = np.arange(len(right.coords)) self.segment_len = np.array([0] + [ co.Vec2d(coord).distance_to(co.Vec2d(line_string.coords[i])) for i, coord in enumerate(line_string.coords[1:]) ]) rd_len = len(line_string.coords) self.dist = np.zeros((rd_len)) for i in range(1, rd_len): self.dist[i] = self.dist[i - 1] + self.segment_len[i] # Top Surface face = [] x = 0. for i, n in enumerate(nodes_l): face.append((n + o, x, 0.5)) o += len(left.coords) for i, n in enumerate(nodes_r): face.append((n + o, x, 0.75)) obj.face(face[::-1]) # Build bottom left line idx_bottom_left = obj.next_node_index() e = self.elevation - 1 for p in left.coords: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) # Build bottom right line idx_bottom_right = obj.next_node_index() for p in right.coords: obj.node(-p[1] + offset.y, e, -p[0] + offset.x) idx_end = obj.next_node_index() - 1 # Build Sides for i, n in enumerate(nodes_l[1:]): # Start with Second point looking back sideface = list() sideface.append((n + idx_bottom_left, x, 0.5)) sideface.append((n + idx_bottom_left - 1, x, 0.5)) sideface.append((n + idx_left - 1, x, 0.5)) sideface.append((n + idx_left, x, 0.5)) obj.face(sideface) for i, n in enumerate(nodes_r[1:]): # Start with Second point looking back sideface = list() sideface.append((n + idx_bottom_right, x, 0.5)) sideface.append((n + idx_bottom_right - 1, x, 0.5)) sideface.append((n + idx_right - 1, x, 0.5)) sideface.append((n + idx_right, x, 0.5)) obj.face(sideface) # Build Front&Back sideface = list() sideface.append((idx_left, x, 0.5)) sideface.append((idx_bottom_left, x, 0.5)) sideface.append((idx_end, x, 0.5)) sideface.append((idx_bottom_left - 1, x, 0.5)) obj.face(sideface) sideface = list() sideface.append((idx_bottom_right, x, 0.5)) sideface.append((idx_bottom_right - 1, x, 0.5)) sideface.append((idx_right - 1, x, 0.5)) sideface.append((idx_right, x, 0.5)) obj.face(sideface)
def probe(self, position: Tuple[float, float], is_global: bool = False) -> Tuple[float, bool]: """Return elevation and ground solidness at (x,y). We try our cache first. Failing that, call Fgelev. Elevation is in meters as float. Solid is True, in water is False """ def really_probe(a_position: co.Vec2d) -> Tuple[float, bool]: if not self.fgelev_pipe: self._open_fgelev() if math.isnan(a_position.lon) or math.isnan(a_position.lat): logging.error("Nan encountered while probing elevation") return -9999, True try: self.fgelev_pipe.stdin.write( "%i %1.10f %1.10f\r\n" % (self.record, a_position.lon, a_position.lat)) except IOError as reason: logging.error(reason) empty_lines = 0 line = "" try: while line == "" and empty_lines < 20: empty_lines += 1 line = self.fgelev_pipe.stdout.readline().strip() if line.startswith('Now checking') or line.startswith('osg::Registry::addImageProcessor') or \ line.startswith('Loaded plug-in'): # New in FG Git version end of Dec 20188 line = "" parts = line.split() elev = float(parts[1]) + self.h_offset is_solid = True if parameters.PROBE_FOR_WATER: if len(parts) == 3: if parts[2] == '-': is_solid = False else: logging.debug( 'ERROR: Probing for water with fgelev missed to return value for water: %s', line) except IndexError as reason: self.close() if empty_lines > 1: logging.fatal("Skipped %i lines" % empty_lines) logging.fatal("%i %g %g" % (self.record, a_position.lon, a_position.lat)) logging.fatal( "fgelev returned <%s>, resulting in %s. Did fgelev start OK (Record : %i)?", line, reason, self.record) raise RuntimeError("fgelev errors are fatal.") return elev, is_solid if parameters.NO_ELEV: return 0, True if not is_global: position = co.Vec2d(self.coords_transform.to_global(position)) else: position = co.Vec2d(position[0], position[1]) self.record += 1 if self._cache is None: return really_probe(position) key = (position.lon, position.lat) try: elev_is_solid_tuple = self._cache[key] return elev_is_solid_tuple except KeyError: elev_is_solid_tuple = really_probe(position) self._cache[key] = elev_is_solid_tuple if self.auto_save_every and len( self._cache) % self.auto_save_every == 0: self._save_cache() return elev_is_solid_tuple