Пример #1
0
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
Пример #2
0
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
Пример #3
0
 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)
Пример #4
0
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)
Пример #5
0
    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)
Пример #6
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.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])
Пример #7
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])
Пример #8
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])
Пример #9
0
def get_center_global():
    cmin = co.Vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH)
    cmax = co.Vec2d(BOUNDARY_EAST, BOUNDARY_NORTH)
    return (cmin + cmax) * 0.5
Пример #10
0
    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)
Пример #11
0
    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