Пример #1
0
    private void DoTestForPhase(double fromPhase, double toPhase)
    {
        const float    mass        = 1000f;
        const bool     reverse     = false;
        GameObject     star        = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0));
        NBody          starNbody   = star.GetComponent <NBody>();
        float          orbitRadius = 20f;
        GameObject     planet      = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 0f, orbitRadius);
        OrbitUniversal orbitU      = planet.GetComponent <OrbitUniversal>();

        orbitU.phase = fromPhase;
        orbitU.SetMajorAxisInspector(orbitRadius);

        orbitRadius = 30.0f;
        GameObject     planet2 = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 0f, orbitRadius);
        OrbitUniversal orbitU2 = planet2.GetComponent <OrbitUniversal>();

        orbitU2.phase = toPhase;
        orbitU2.SetMajorAxisInspector(orbitRadius);

        GravityEngine.Instance().UnitTestAwake();
        GravityEngine.Instance().AddBody(star);
        GravityEngine.Instance().AddBody(planet);
        GravityEngine.Instance().AddBody(planet2);
        GravityEngine.Instance().Setup();

        Debug.Log("Find transfers");
        OrbitData        fromOrbit = new OrbitData(orbitU);
        OrbitData        toOrbit   = new OrbitData(orbitU2);
        LambertUniversal lambertU  = new LambertUniversal(fromOrbit, toOrbit, true);

        Assert.AreNotEqual(lambertU, null);
        double time = 0.8f * lambertU.GetTMin();

        lambertU.ComputeXfer(reverse, false, 0, time);
        LambertBattin lambertB = new LambertBattin(fromOrbit, toOrbit);
        int           error    = lambertB.ComputeXfer(reverse, false, 0, time);

        Assert.AreEqual(error, 0);
        Assert.AreNotEqual(lambertB, null);
        Assert.AreNotEqual(lambertB.GetTransferVelocity(), null);
        Debug.LogFormat("initial velocity {0} vs {1}", lambertU.GetTransferVelocity(), lambertB.GetTransferVelocity());
        Debug.LogFormat("initial velocity mag {0} vs {1}",
                        lambertU.GetTransferVelocity().magnitude, lambertB.GetTransferVelocity().magnitude);
        Debug.LogFormat("final velocity {0} vs {1}", lambertU.GetFinalVelocity(), lambertB.GetFinalVelocity());
        Debug.LogFormat("final velocity mag {0} vs {1}",
                        lambertU.GetFinalVelocity().magnitude, lambertB.GetFinalVelocity().magnitude);
        // best can do for 180 degree case is E-2 accuracy on the magnitude. Not sure why...seems too big
        Assert.IsTrue(GEUnit.DoubleEqual(lambertU.GetTransferVelocity().magnitude,
                                         lambertB.GetTransferVelocity().magnitude,
                                         1E-2));
    }
    /// <summary>
    /// Computes the transfer and updates all the ghost bodies.
    /// </summary>
    /// <returns></returns>
    private void ComputeTransfer()
    {
        double timeNow = ge.GetPhysicalTimeDouble();

        // First using the transfer time, move the ghost Moon to position at SOI arrival.
        // Call evolve via LockAtTime on the ghostMoon to move it. Set position based on this.
        double t_flight  = tflightFactor * timeHohmann;
        double timeatSoi = timeNow + t_flight;

        ghostMoonOrbit[MOON_SOI_ENTER].LockAtTime(timeatSoi);
        // Determine the moon phase angle
        double moonPhase = ghostMoonSoiEnterOrbitPredictor.GetOrbitUniversal().phase;

        // Place the TLI ship at the user-requested angle wrt planet-moon line
        // Put ghost ship in same orbit geometry as the moon, assuming it is circular. Then
        // can use same phase value.
        // (Ship needs to reach this departure point, it may not even be on the ship orbit
        //  in general).
        ghostShipOrbit[TLI].phase       = shipTLIAngleDeg + (moonPhase + 180f);
        ghostShipOrbit[TLI].inclination = ghostMoonOrbit[MOON_SOI_ENTER].inclination;
        ghostShipOrbit[TLI].omega_lc    = ghostMoonOrbit[MOON_SOI_ENTER].omega_lc;
        ghostShipOrbit[TLI].omega_uc    = ghostMoonOrbit[MOON_SOI_ENTER].omega_uc;
        ghostShipOrbit[TLI].p_inspector = shipOrbit.p;
        ghostShipOrbit[TLI].Init();
        ghostShipOrbit[TLI].LockAtTime(0);

        // Place the SOI enter ship at the user-requested angle in an SOI orbit. Lock at time 0 so the phase
        // is held per the user input.
        ghostShipOrbit[ENTER_SOI].phase       = soiAngleDeg + moonPhase;
        ghostShipOrbit[ENTER_SOI].inclination = soiInclination + shipOrbit.inclination;
        ghostShipOrbit[ENTER_SOI].omega_lc    = ghostMoonOrbit[MOON_SOI_ENTER].omega_lc;
        ghostShipOrbit[ENTER_SOI].omega_uc    = ghostMoonOrbit[MOON_SOI_ENTER].omega_uc;
        ghostShipOrbit[ENTER_SOI].Init();
        ghostShipOrbit[ENTER_SOI].LockAtTime(0);

        // Find the line to the ENTER_SOI position. Ship departs from that line continued through planet
        // at the shipRadius distance (assumes circular ship orbit)
        // TODO: Handle planet not at (0,0,0)
        Vector3d soiEntryPos    = ge.GetPositionDoubleV3(ghostShip[ENTER_SOI]);
        Vector3d planetPos      = ge.GetPositionDoubleV3(planet);
        Vector3d departurePoint = ge.GetPositionDoubleV3(ghostShip[TLI]);

        // Use Lambert to find the departure velocity to get from departure to soiEntry
        // Since we need 180 degrees from departure to arrival, use LambertBattin
        lambertB = new LambertBattin(ghostShip[TO_MOON], planet, departurePoint, soiEntryPos, shipOrbit.GetAxis());

        // apply any time of flight change
        bool reverse = !shortPath;

        const bool df    = false;
        const int  nrev  = 0;
        int        error = lambertB.ComputeXfer(reverse, df, nrev, t_flight);

        if (error != 0)
        {
            Debug.LogWarning("Lambert failed to find solution. error=" + error);
            return;
        }
        // Check Lambert is going in the correct direction
        //Vector3 shipOrbitAxis = Vector3.Cross(ge.GetPhysicsPosition(spaceship), ge.GetVelocity(spaceship) ).normalized;
        //Vector3 tliOrbitAxis = Vector3.Cross(departurePoint.ToVector3(), lambertB.GetTransferVelocity().ToVector3()).normalized;
        Vector3 shipOrbitAxis = Vector3.Cross(ge.GetVelocity(spaceship), ge.GetPhysicsPosition(spaceship)).normalized;
        Vector3 tliOrbitAxis  = Vector3.Cross(lambertB.GetTransferVelocity().ToVector3(), departurePoint.ToVector3()).normalized;

        if (Vector3.Dot(shipOrbitAxis, tliOrbitAxis) < 0)
        {
            error = lambertB.ComputeXfer(!reverse, df, nrev, t_flight);
            if (error != 0)
            {
                Debug.LogWarning("Lambert failed to find solution for reverse path. error=" + error);
                return;
            }
        }
        Debug.LogFormat("tli_vel={0}", lambertB.GetTransferVelocity());

        ghostShipOrbit[TO_MOON].InitFromRVT(departurePoint, lambertB.GetTransferVelocity(), timeNow, planet, false);

        // Set velocity for orbit around moon. Will be updated every frame
        ghostShipOrbit[SOI_HYPER].InitFromRVT(soiEntryPos, lambertB.GetFinalVelocity(), timeNow, ghostMoon[MOON_SOI_ENTER], false);

        // Find the exit point of the hyperbola in the SOI
        OrbitUtils.OrbitElements oe = OrbitUtils.RVtoCOE(soiEntryPos, lambertB.GetFinalVelocity(), ghostMoon[MOON_SOI_ENTER], false);
        Vector3d soiExitR           = new Vector3d();
        Vector3d soiExitV           = new Vector3d();

        OrbitUtils.COEtoRVMirror(oe, ghostMoon[MOON_SOI_ENTER], ref soiExitR, ref soiExitV, false);

        // Find time to go around the moon. TOF requires relative positions!!
        Vector3d ghostSoiEnterPos   = ge.GetPositionDoubleV3(ghostMoon[MOON_SOI_ENTER]);
        Vector3d soiEnterRelative   = soiEntryPos - ghostSoiEnterPos;
        Vector3d soiExitRelative    = soiExitR - ghostSoiEnterPos;
        Vector3d soiExitVelRelative = soiExitV - ge.GetVelocityDoubleV3(ghostMoon[MOON_SOI_ENTER]);
        double   hyperTOF           = ghostShipOrbit[SOI_HYPER].TimeOfFlight(soiEnterRelative, soiExitRelative);

        // Position the ghost moon for SOI exit (timeAtSoi includes timeNow)
        t_soiExit = timeatSoi + hyperTOF;
        ghostMoonOrbit[MOON_SOI_EXIT].LockAtTime(t_soiExit);

        // Set position and vel for exit ship, so exit orbit predictor can run.
        Vector3d ghostMoonSoiExitPos = ge.GetPositionDoubleV3(ghostMoon[MOON_SOI_EXIT]);
        Vector3d ghostMoonSoiExitVel = ge.GetVelocityDoubleV3(ghostMoon[MOON_SOI_EXIT]);

        ghostShipOrbit[EXIT_SOI].InitFromRVT(soiExitRelative + ghostMoonSoiExitPos,
                                             soiExitVelRelative + ghostMoonSoiExitVel,
                                             timeNow, planet, false);
    }