def get_course_towards(self, point): ''' Get the heading of a direct vector towards a given point. ''' assert isinstance(point, Vector3) delta = point - self.plane.position return U.v3_to_heading(delta)
def testVector2Heading(self): ''' v3_to_heading - heading of a vector ''' TOTEST = [((0, 1, -27), 0), ((0, -1, +0.57), 180), ((1, 1, 0), 45), ((-10, 10, 0), 315), ] for vector, result in TOTEST: vector = Vector3(*vector) self.assertEqual(U.v3_to_heading(vector), result)
def _initiate(self, commands): ''' Automatically called by ancestor class upon ``__init__`` ''' pl = self.plane aspace = pl.aerospace r_name = commands['TAKEOFF'][0][0] port = aspace.airports[pl.origin] runway = port.runways[r_name] twin = port.runways[runway['twin']] start_point = runway['location'] + port.location vector = Vector3(*(-twin['ils']).normalized().xy) self.end_of_runway = twin['location'] + port.location # SAVE PROCEDURE' PERSISTENT DATA h = commands['HEADING'][0][0] if 'HEADING' in commands \ else U.v3_to_heading(vector) a = commands['ALTITUDE'][0][0] if 'ALTITUDE' in commands \ else pl.max_altitude self.target_heading = h self.target_altitude = a self.timer = S.RUNWAY_BUSY_TIME # LET'S ROLL!! pl.position = start_point.copy() aspace.runways_manager.use_runway(port, twin, pl) pl.flags.locked = True # Give 1 m/s speed and update target to set the heading/sprite icon pl.velocity = vector.copy() self.pilot.set_target_conf_to_current() # Set max acceleration self.pilot.target_conf.speed = \ commands['SPEED'][0][0] if 'SPEED' in commands else pl.max_speed self.phase = self.ACCELERATING # LOG log.info('%s is taking off from %s %s' % (pl.icao, pl.origin, runway['name'])) if self._check_expedite(commands): self.pilot.status['haste'] = 'expedite'
def _initiate(self, commands): ''' Automatically called by ancestor class upon ``__init__`` ''' pl = self.plane pi = self.pilot port_name, rnwy_name = commands['LAND'][0] self.lander = Lander(self.pilot, port_name, rnwy_name) l = self.lander # EARLY RETURN - Maximum incidence angle into the ILS is 60° ils_heading = U.v3_to_heading(l.ils) boundaries = [(ils_heading - S.ILS_TOLERANCE)%360, (ils_heading + S.ILS_TOLERANCE)%360] if not U.heading_in_between(boundaries, pl.heading): msg = 'ILS heading must be within %s degrees ' \ 'from current heading' % S.ILS_TOLERANCE return self._abort_landing(msg) # EARLY RETURN - No possible intersection (the RADAR_RANGE*3 # ensures that the segments to test for intersection are long enough. if not l.set_intersection_point(): msg = 'The ILS does not intersect the plane current heading' return self._abort_landing(msg) # EARLY RETURN - Although the intersection is ahead of the plane, # it's too late to merge into the ILS vector type_ = pi.status['haste'] if l.set_merge_point(pi.navigator.get_veering_radius(type_)) < 0: msg = 'We are too close to the ILS to merge into it' return self._abort_landing(msg) # LANDING IS NOT EXCLUDED A PRIORI... log.info('%s started landing procedure, destination: %s %s' % (self.plane.icao, port_name, rnwy_name)) # SETTING PERSISTENT DATA if self._check_expedite(commands): pi.status['haste'] = 'expedite' self.phase = self.INTERCEPTING self.lander = l
def set_merge_point(self, radius): ''' Set and return self.mp, the 2D point where the plane should begin merging into the ILS vector. ''' # From the geometrical construction it is possible to observe that the # correct distance from the intersection point with a course for # merging into it is the cathetus of a triangle whose other cathetus is # the veering radius and whose adiacent angle is (180°-head_diff)/2, in # which head_diff is the difference between the current heading and the # target one. Since tan(angle) = opposite/adjacent the we solve for # adjacent with = adjacent = opposite/tan(angle) h1 = self.plane.heading h2 = U.v3_to_heading(self.ils) a1 = abs((h1-h2)%360) a2 = abs((h2-h1)%360) angle = min(a1, a2) angle = radians((180 - angle) / 2.0) dist_from_ip = radius/tan(angle) dist_from_plane = abs(self.ip-self.plane.position)-dist_from_ip self.mp = self.pilot.navigator.get_point_ahead(dist_from_plane) if self.pilot.navigator.check_overshot(self.mp) == True: self.mp = None return self.mp
def heading(self): '''Current heading [CW degrees from North]''' return U.v3_to_heading(self.velocity)