private void TestRV(OrbitData od, GameObject planet, GameObject star)
    {
        GameObject testPlanet = TestSetupUtils.CreatePlanetInHyper(star, 1f);

        testPlanet.name = "TestPlanet";
        OrbitHyper testHyper = testPlanet.GetComponent <OrbitHyper>();

        testHyper.InitFromOrbitData(od);

        planet.name = "Planet";

        // Awkward but cannot add a new object to GE when it is stopped, so re-add all three
        GravityEngine ge = GravityEngine.Instance();

        ge.Clear();
        ge.AddBody(star);
        ge.AddBody(planet);
        ge.AddBody(testPlanet);
        ge.Setup();
        ge.LogDump();
        Vector3 r_od = ge.GetPhysicsPosition(testPlanet.GetComponent <NBody>());
        Vector3 v_od = ge.GetVelocity(testPlanet);
        Vector3 r_i  = ge.GetPhysicsPosition(planet.GetComponent <NBody>());
        Vector3 v_i  = ge.GetVelocity(planet);

        Debug.Log(" r_i=" + r_i + " r_od=" + r_od + " delta=" + Vector3.Distance(r_i, r_od));
        Debug.Log(" v_i=" + v_i + " v_od=" + v_od + " delta=" + Vector3.Distance(v_i, v_od));
        Assert.IsTrue(FloatEqual(Vector3.Distance(r_i, r_od), 0f, 5E-2));
        Assert.IsTrue(FloatEqual(Vector3.Distance(v_i, v_od), 0f, 5E-2));
    }
    private void TestRV(OrbitData od, GameObject planet, NBody starNbody, float orbitRadius)
    {
        GameObject     testPlanet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius);
        OrbitUniversal orbitU     = testPlanet.GetComponent <OrbitUniversal>();

        // Run init explicitly to update transform details
        orbitU.InitFromOrbitData(od, 0);

        // Awkward but previously could not add a new object to GE when it is stopped, so re-add all three
        // Leave as is, since it works!
        GravityEngine ge = GravityEngine.Instance();

        ge.Clear();
        ge.AddBody(starNbody.gameObject);
        ge.AddBody(planet);
        ge.AddBody(testPlanet);
        ge.Setup();
        ge.LogDump();
        Vector3 r_od = ge.GetPhysicsPosition(testPlanet.GetComponent <NBody>());
        Vector3 v_od = ge.GetVelocity(testPlanet);
        Vector3 r_i  = ge.GetPhysicsPosition(planet.GetComponent <NBody>());
        Vector3 v_i  = ge.GetVelocity(planet);

        Debug.Log(" r_i=" + r_i + " r_od=" + r_od + " delta=" + Vector3.Distance(r_i, r_od));
        Debug.Log(" v_i=" + v_i + " v_od=" + v_od + " delta=" + Vector3.Distance(v_i, v_od));
        Assert.IsTrue(GEUnit.FloatEqual(Vector3.Distance(r_i, r_od), 0f, 1E-2));
        Assert.IsTrue(GEUnit.FloatEqual(Vector3.Distance(v_i, v_od), 0f, 1E-2));
    }
    private void TestRV(OrbitData od, GameObject planet, GameObject star, float orbitRadius)
    {
        GameObject   testPlanet  = TestSetupUtils.CreatePlanetInOrbit(star, 1f, orbitRadius);
        OrbitEllipse testEllipse = testPlanet.GetComponent <OrbitEllipse>();

        // Run init explicitly to update transform details
        testEllipse.InitFromOrbitData(od);

        // Awkward but cannot add a new object to GE when it is stopped, so re-add all three
        GravityEngine ge = GravityEngine.Instance();

        ge.Clear();
        ge.AddBody(star);
        ge.AddBody(planet);
        ge.AddBody(testPlanet);
        ge.Setup();
        ge.LogDump();
        Vector3 r_od = ge.GetPhysicsPosition(testPlanet.GetComponent <NBody>());
        Vector3 v_od = ge.GetVelocity(testPlanet);
        Vector3 r_i  = ge.GetPhysicsPosition(planet.GetComponent <NBody>());
        Vector3 v_i  = ge.GetVelocity(planet);

        Debug.Log(" r_i=" + r_i + " r_od=" + r_od + " delta=" + Vector3.Distance(r_i, r_od));
        Debug.Log(" v_i=" + v_i + " v_od=" + v_od + " delta=" + Vector3.Distance(v_i, v_od));
        Assert.IsTrue(FloatEqual(Vector3.Distance(r_i, r_od), 0f, 1E-2));
        Assert.IsTrue(FloatEqual(Vector3.Distance(v_i, v_od), 0f, 1E-2));
    }
Beispiel #4
0
 public string DumpAll(NBody[] gameNBodies, GravityEngine ge)
 {
     System.Text.StringBuilder sb = new System.Text.StringBuilder();
     sb.Append("Massive Bodies:\n");
     for (int i = 0; i < numBodies; i++)
     {
         Vector3 vel         = ge.GetVelocity(gameNBodies[i]);
         int     engineIndex = gameNBodies[i].engineRef.index;
         sb.Append(string.Format("   n={0} {1} m={2} r={3} {4} {5} v={6} {7} {8} info={9} engineRef.index={10} extAcc={11}\n",
                                 i, gameNBodies[i].name,
                                 m[i], r[i, 0], r[i, 1], r[i, 2],
                                 vel.x, vel.y, vel.z, info[i], engineIndex, integrator.GetExternalAccelForIndex(engineIndex)
                                 ));
     }
     // Title printed by MBE
     if (masslessEngine != null)
     {
         sb.Append(masslessEngine.DumpString());
     }
     sb.Append("Fixed Bodies:\n");
     for (int i = 0; i < fixedBodies.Count; i++)
     {
         int fb_index = fixedBodies[i].nbody.engineRef.index;
         sb.Append(string.Format("   n={0} {1} kepler_depth={2}\n",
                                 i,
                                 gameNBodies[fb_index].name,
                                 fixedBodies[i].kepler_depth));
         // add extra info if OrbitU or KeplerSeq
         sb.Append(fixedBodies[i].nbody.engineRef.fixedBody.fixedOrbit.DumpInfo());
     }
     sb.Append(" fixedBodiesInIntegrator=" + fixedBodiesInIntegrator);
     // Any pending maneuvers - TODO
     // sb.Append(maneuverMgr.DumpAll());
     return(sb.ToString());
 }
Beispiel #5
0
    /// <summary>
    /// Execute the maneuver. Called automatically by Gravity Engine for maneuvers that
    /// have been added to the GE via AddManeuver().
    ///
    /// Unusual to call this method directly.
    /// </summary>
    /// <param name="ge"></param>
    public void Execute(GravityEngine ge)
    {
        Vector3 vel = ge.GetVelocity(nbody);

        switch (mtype)
        {
        case Mtype.vector:
            vel += velChange;
            break;

        case Mtype.scalar:
            // scalar: adjust existing velocity by dV
            Vector3 change = Vector3.Normalize(vel) * dV;
            vel += change;
            break;

        case Mtype.circularize:
            // find velocity vector perpendicular to r for circular orbit
            // Since we could be mid-integration need to get exact position from GE
            double[] r_ship = new double[3];
            double[] v_ship = new double[3];
            ge.GetPositionVelocityScaled(nbody, ref r_ship, ref v_ship);
            double[] r_center = new double[3];
            double[] v_center = new double[3];
            ge.GetPositionVelocityScaled(centerBody, ref r_center, ref v_center);

            Vector3 pos_ship   = new Vector3((float)r_ship[0], (float)r_ship[1], (float)r_ship[2]);
            Vector3 vel_ship   = new Vector3((float)v_ship[0], (float)v_ship[1], (float)v_ship[2]);
            Vector3 pos_center = new Vector3((float)r_center[0], (float)r_center[1], (float)r_center[2]);
            Vector3 r          = pos_ship - pos_center;

            // to get axis of orbit, can take v x r
            Vector3 axis = Vector3.Normalize(Vector3.Cross(vel_ship, pos_ship));
            // vis visa for circular orbit
            float mu    = nbody.mass * ge.massScale;
            float v_mag = Mathf.Sqrt(mu / Vector3.Magnitude(r));
            // positive v is counter-clockwise
            Vector3 v_dir      = Vector3.Normalize(Vector3.Cross(axis, r));
            Vector3 v_circular = v_mag * v_dir;
            ge.SetVelocity(nbody, v_circular);

            break;
        }
#pragma warning disable 162        // disable unreachable code warning
        if (GravityEngine.DEBUG)
        {
            Debug.Log("Applied manuever: " + LogString() + " engineRef.index=" + nbody.engineRef.index +
                      " engineRef.bodyType=" + nbody.engineRef.bodyType + " timeError=" + (worldTime - ge.GetPhysicalTime()));
            Debug.Log("r= " + Vector3.Magnitude(nbody.transform.position));
        }
#pragma warning restore 162        // enable unreachable code warning

        ge.SetVelocity(nbody, vel);
    }
    // If there is no init delegate use the initial particle position (scaled to physics space) and the
    // initial particle velocity to seed the particle physics data.
    private void NoInitDelegateSetup(int fromP, int toP)
    {
        float   scale          = gravityEngine.physToWorldFactor;
        Vector3 sourceVelocity = Vector3.zero;

        if (addNBodyVelocity && nbodySource != null)
        {
            sourceVelocity = gravityEngine.GetVelocity(nbodySource);
        }
        sourceVelocity += initialVelocity;
        for (int i = fromP; i < toP; i++)
        {
            // particles are in world space - just use their position
            r[i, 0]               = (particles[i].position.x) / scale;
            r[i, 1]               = (particles[i].position.y) / scale;
            r[i, 2]               = (particles[i].position.z) / scale;
            v[i, 0]               = sourceVelocity.x + particles[i].velocity.x;
            v[i, 1]               = sourceVelocity.y + particles[i].velocity.y;
            v[i, 2]               = sourceVelocity.z + particles[i].velocity.z;
            inactive[i]           = false;
            particles[i].velocity = Vector3.zero;
        }
    }
    /// <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);
    }
    /// <summary>
    /// Computes the transfer with the moon on the +X axis without accounting for the moon motion during
    /// transit. (That is accounted for in the ExecuteTransfer routine).
    ///
    /// This allows a co-rotating visualization of the orbit.
    /// </summary>
    /// <returns></returns>
    private Vector3 ComputeTransfer()
    {
        OrbitData shipOrbit = new OrbitData();

        shipOrbit.SetOrbitForVelocity(spaceship, planet);

        // compute the min energy path (this will be in the short path direction)
        lambertU = new LambertUniversal(shipOrbit, startPoint, targetPoint, shortPath);

        // apply any time of flight change
        double t_flight = tflightFactor * lambertU.GetTMin();
        bool   reverse  = !shortPath;

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

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

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

        Vector3 tliVelocity = lambertU.GetTransferVelocity();

        toMoonOrbit.SetVelocity(tliVelocity);
        toMoonSegment.SetVelocity(tliVelocity);
        aroundMoonSegment.gameObject.SetActive(true);

        // Set velocity for orbit around moon
        Vector3 soiEnterVel = lambertU.GetFinalVelocity();

        aroundMoonSegment.SetVelocity(soiEnterVel);

        // update shipEnterSOI object
        ge.UpdatePositionAndVelocity(shipEnterSOI, targetPoint.ToVector3(), soiEnterVel);

        // Find the orbit around the moon. By using the mirror position we're assuming it's
        // a hyperbola (since there is no course correction at SOI this is true).
        // (Moon is in correct position for these calcs so can use world positions, relativePos=false)
        Vector3d soiEnterV = new Vector3d(lambertU.GetFinalVelocity());

        OrbitUtils.OrbitElements oe = OrbitUtils.RVtoCOE(targetPoint, soiEnterV, moonBody, false);
        Vector3d soiExitR           = new Vector3d();
        Vector3d soiExitV           = new Vector3d();

        OrbitUtils.COEtoRVMirror(oe, moonBody, ref soiExitR, ref soiExitV, false);
        // Set position and vel for exit ship, so exit orbit predictor can run. Moon offset/vel already added.
        ge.SetPositionDoubleV3(shipExitSOI, soiExitR);
        ge.SetVelocityDoubleV3(shipExitSOI, soiExitV);
        aroundMoonSegment.UpdateOrbit();
        return(tliVelocity);
    }
    // Update is called once per frame
    void Update()
    {
        Vector3 v = ge.GetVelocity(nbody.gameObject);

        transform.rotation = Quaternion.FromToRotation(axis.normalized, v.normalized);
    }