コード例 #1
0
 def thrust_direction(axis: int, force: float, pr: Projectile):
     if pr.time < 1.2:
         return spherical_to_planar_coord(axis, force, math.pi / 4, 0)
     if (pr.position.alt > 100000
             or pr.velocities[Z_INDEX] > 4000) and pr.pitch > 0.2:
         spherical_to_planar_coord(axis, force, pr.pitch - 0.15, pr.yaw)
     if pr.pitch < 0.15:
         spherical_to_planar_coord(axis, force, pr.pitch + 0.17, pr.yaw)
     return follow_path(axis, force, pr)
コード例 #2
0
def follow_path(axis: int, force: float, pr: Projectile) -> float:
    return spherical_to_planar_coord(axis, force, pr.pitch, pr.yaw)
コード例 #3
0
    def update_velocities(self, old_lat: np.float128, old_lon: np.float128,
                          radius: float, distance_m: float) -> None:
        """
        Update velocities: take a look at the old position, current position, how much it has changed and calculate the
        speed based on that. Effectively moves the local tangent plane. z-speed is not modified as it's unaffected by
        moving of the tangent plane.
        :param old_lat: previous latitude
        :param old_lon: previous longitude
        :param radius: earth radius + altitude
        :param distance_m: distance travelled (could be calculated inside the function, but no need atm)
        :return: nothing; updates the projectile's state
        """
        old_vy = self.velocities[Y_INDEX]
        self.velocities[Y_INDEX] = (radius * (self.position.lat - old_lat)
                                    ) / self.dt  # usual case for correcting Vy
        # our first and largest problem is detecting whether we've crossed the pole. I don't know a nice way for this,
        # so we use the ugly way: statistics and prayers.
        # ideally, change_radio should be 0 (meaning Vy won't be corrected)
        if old_vy != 0:
            change_ratio = fabs(self.velocities[Y_INDEX] / old_vy - 1)
        else:
            change_ratio = fabs(self.velocities[Y_INDEX])
        if change_ratio > self.vy_corrective_change_threshold:  # oops, we've modified Vy too much
            actual_distance = haversine(self.position,
                                        Position(old_lat, old_lon, 0), radius)
            if self.crossed_the_pole:  # if we've crossed the pole recently, we definitely don't want to do it again
                print(
                    f"Warning! V_y has too extreme oscillations: {change_ratio}"
                )
            elif actual_distance < self.distance_stats.mean and self.distance_stats.is_outlier(
                    actual_distance):
                # if we've travelled significantly less than usual (i.e. in y direction), assume we've crossed the pole
                # conceptually simple, practically not-really-definable, but surprisingly effective
                print(f"Crossing the pole: change ratio is {change_ratio}f")
                # so now that we've crossed the pole, we want to reverse Vx and Vy and change longitude so we continue
                # flying 'straight'. We're basically throwing away this iteration and using the data from the previous.
                self.crossed_the_pole = True  # this will prevent crossing the pole again if we're still too close
                self.position.lon = divmod((old_lon + pi),
                                           (2 * pi))[1] - 2 * pi
                self.yaw = self.yaw - pi % (sgn(self.yaw - pi) * 2 * pi)
                self.velocities[X_INDEX] = spherical_to_planar_coord(
                    X_INDEX, self.total_velocity, self.pitch, self.yaw)
                self.velocities[Y_INDEX] = spherical_to_planar_coord(
                    Y_INDEX, self.total_velocity, self.pitch, self.yaw)
                return  # don't update X velocity!
            elif actual_distance < self.distance_stats.mean:
                # Vy changed a lot, but we're far away from the pole; can happen in e.g. polar circle even if we're not
                # flying over the pole itself.
                print(
                    f"Warning: Vy has extreme correction, but we're far from poles: {change_ratio}"
                )
        if self.crossed_the_pole:
            self.crossed_the_pole = False
            self.velocities[
                Y_INDEX] = old_vy  # don't correct speed if we've just skipped the pole
            return

        self.distance_stats.update(
            distance_m)  # we need to keep track of what's the 'usual' movement
        # from now on, we take care of updating Vx
        lon_radius = radius * cos(self.position.lat)
        if lon_radius == 0:
            # not much we can do if we're exactly at the pole, just use the last good number, it'll be close enough
            lon_radius = radius * cos(old_lat)
        if fabs(self.position.lon -
                old_lon) < pi:  # usual case for correcting Vx
            self.velocities[X_INDEX] = (
                lon_radius * (self.position.lon - old_lon)) / self.dt
        else:  # crossing the antimeridian: we haven't really moved for 2pi, so substract (or add) that
            self.velocities[X_INDEX] = (
                lon_radius *
                (self.position.lon - old_lon +
                 2 * pi * sgn(old_lon - self.position.lon))) / self.dt