Beispiel #1
0
    public void InitNewParticles(int fromParticle, int toParticle, ref double [,] r, ref double[,] v)
    {
                #pragma warning disable 162             // disable unreachable code warning
        if (GravityEngine.DEBUG)
        {
            Debug.Log("Create explosion: contact=" + contactPoint + " normal=" + normal);
        }
                #pragma warning restore 162

        for (int i = fromParticle; i < toParticle; i++)
        {
            r[i, 0] = (float)contactPoint.x;
            r[i, 1] = (float)contactPoint.y;
            r[i, 2] = (float)contactPoint.z;
            // to generate the velocity for cone around z-axis then rotate into place
            float   offset         = Mathf.Sin(Mathf.Deg2Rad * coneWidth) * Random.value;
            float   angle          = 2f * Mathf.PI * Random.value;
            Vector3 velocity       = new Vector3(offset * Mathf.Sin(angle), offset * Mathf.Cos(angle), 1f);
            float   velocityScale  = NUtils.GaussianValue(explosionVelocity, velocitySpread);
            Vector3 scaledVelocity = velocityScale * Vector3.Normalize(velocity);
            Vector3 finalVelocity  = rotateToNormal * scaledVelocity + bodyVelocity;
            v[i, 0] = (float)finalVelocity.x;
            v[i, 1] = (float)finalVelocity.y;
            v[i, 2] = (float)finalVelocity.z;
        }
                #pragma warning disable 162
        if (GravityEngine.DEBUG)
        {
            Debug.Log(string.Format("Explosion particle 0: v=({0} ,{1}, {2}) x=({3}, {4}, {5} vesc={6} vmag={7})",
                                    v[0, 0], v[0, 1], v[0, 2], r[0, 0], r[0, 1], r[0, 2], explosionVelocity,
                                    System.Math.Sqrt(v[0, 0] * v[0, 0] + v[0, 1] * v[0, 1] + v[0, 2] * v[0, 2])));
        }
                #pragma warning restore 162
    }
Beispiel #2
0
    /// <summary>
    /// Convert Mean Anomoly to True Anomoly for an ellipse with eccentricity e.
    /// </summary>
    /// <returns>True Anomoly in degrees.</returns>
    /// <param name="m">Mean Anomoly. (degrees)</param>
    /// <param name="e">Eccentricty.</param>
    public static float MeanToTrueAnomoly(float m, float e)
    {
        int   loopCount = 0;
        float u         = m * Mathf.Deg2Rad; // seed with mean anomoly
        float u_next    = 0;
        // some extreme comet orbits (e.g. Halley) need a LOT of iterations
        const int LOOP_LIMIT = 200;

        while (loopCount++ < LOOP_LIMIT)
        {
            // this should always converge in a small number of iterations - but be paranoid
            u_next = u + (m - (u - e * Mathf.Sin(u))) / (1 - e * Mathf.Cos(u));
            if (Mathf.Abs(u_next - u) < 1E-6)
            {
                break;
            }
            u = u_next;
        }
        if (loopCount >= LOOP_LIMIT)
        {
            Debug.LogError("Failed to converge u_n=" + u_next);                 // keep going anyway
        }
        // 2) eccentric anomoly is angle from center of ellipse, not focus (where centerObject is). Convert
        //    to true anomoly, f - the angle measured from the focus. (see Fig 3.2 in Gravity)
        float cos_f = (Mathf.Cos(u) - e) / (1f - e * Mathf.Cos(u));
        float sin_f = (Mathf.Sqrt(1 - e * e) * Mathf.Sin(u)) / (1f - e * Mathf.Cos(u));
        float f_deg = NUtils.AngleFromSinCos(sin_f, cos_f) * Mathf.Rad2Deg;

        //Debug.Log("m=" + m + " E=" + u * Mathf.Deg2Rad + " f=" + f_deg);
        return(f_deg);
    }
    /// <summary>
    /// Calculate an array of orbit positions. Used by the OrbitPredictor, OrbitRenderer and Editor
    /// Gimzo to illustrate the hyperbola.
    /// </summary>
    /// <returns>The positions.</returns>
    /// <param name="numPoints">Number points.</param>
    public Vector3[] OrbitPositions(int numPoints, Vector3 centerPos, bool doSceneMapping)
    {
        CalculateRotation();

        Vector3[] emptyArray = { new Vector3(0, 0, 0), new Vector3(0, 0, 0) };
        // need to have a center to create positions.
        if (centerObject == null)
        {
            centerObject = transform.parent.gameObject;
            if (centerObject == null)
            {
                return(emptyArray);
            }
        }
        Vector3[]     points = new Vector3[numPoints];
        float         theta  = -1f * branchDisplayFactor * Mathf.PI;
        float         dTheta = 2f * Mathf.Abs(theta) / (float)numPoints;
        GravityEngine ge     = GravityEngine.Instance();

        for (int i = 0; i < numPoints; i++)
        {
            points[i] = PositionForThetaLeftBranch(theta, centerPos);
            if (NUtils.VectorNaN(points[i]))
            {
                points[i] = Vector3.zero;
            }
            else if (doSceneMapping && ge.mapToScene)
            {
                points[i] = ge.MapToScene(points[i]);
            }
            theta += dTheta;
        }
        return(points);
    }
    /// <summary>
    /// Use AD/KL to position the arrival symbol on the SOI.
    ///
    /// </summary>
    private bool UpdateManeuverSymbols()
    {
        bool keyPressed = false;

        // ship
        if (Input.GetKey(KeyCode.K))
        {
            soiInclination = (float)NUtils.DegreesPM180(soiInclination + dAngleDegrees);
            keyPressed     = true;
        }
        else if (Input.GetKey(KeyCode.L))
        {
            soiInclination = (float)NUtils.DegreesPM180(soiInclination - dAngleDegrees);
            keyPressed     = true;
        }
        else if (Input.GetKey(KeyCode.A))
        {
            soiAngleDeg = (float)NUtils.DegreesMod360(soiAngleDeg + dAngleDegrees);
            keyPressed  = true;
        }
        else if (Input.GetKey(KeyCode.D))
        {
            soiAngleDeg = (float)NUtils.DegreesMod360(soiAngleDeg - dAngleDegrees);
            keyPressed  = true;
        }

        // update degree values so can see result in inspector
        return(keyPressed);
    }
    /// <summary>
    /// Determine the angle for a position on the hyperbola given the position.
    /// </summary>
    /// <param name="position"></param>
    /// <returns></returns>
    public float ThetaForPosition(Vector3 position, Vector3 cPos)
    {
        Vector3 ellipseAxis = PositionForThetaLeftBranch(0f, cPos);
        Vector3 normal      = hyper_orientation * Vector3.forward;

        return(NUtils.AngleFullCircleRadians(ellipseAxis, position - centerPos, normal));
    }
Beispiel #6
0
 public void PreEvolve(GravityState gravityState, ref byte[] info)
 {
     double[] mass = gravityState.m;
     double[,] pos = gravityState.r;
     Get_acc_jerk_pot_coll(ref mass, ref pos, ref info);
     initialEnergy = NUtils.GetEnergy(numBodies, ref mass, ref pos, ref vel);
 }
    /// <summary>
    /// Calculate an array of points that describe the specified orbit
    /// </summary>
    /// <returns>The positions.</returns>
    /// <param name="numPoints">Number points.</param>
    public Vector3[] OrbitPositions(int numPoints, Vector3 centerPos, bool doSceneMapping)
    {
        GravityEngine ge = GravityEngine.Instance();

        Vector3[] points = new Vector3[numPoints];

        UpdateOrbitParams();
        CalculateRotation();

        float dtheta = 2f * Mathf.PI / numPoints;
        float theta  = 0;

        // add a fudge factor to ensure we go all the way around the circle
        for (int i = 0; i < numPoints; i++)
        {
            points[i] = PositionForTheta(theta, centerPos);
            if (NUtils.VectorNaN(points[i]))
            {
                Debug.LogError("Vector NaN + " + points[i]);
                points[i] = Vector3.zero;
            }
            else if (doSceneMapping && ge.mapToScene)
            {
                points[i] = ge.MapToScene(points[i]);
            }
            theta += dtheta;
        }
        // close the path (credit for fix to R. Vincent)
        points[numPoints - 1] = points[0];
        return(points);
    }
Beispiel #8
0
	public static void SetEllipse(float epoch, EllipseBase ellipseBase, SolarBody sb) {
		// orbital element variation is not provided - only phase to determine
		// What is the delat to the reference epoch?
		float deltaYears = epoch - sb.epoch;
		float period = SolarUtils.GetPeriodYears(sb);
		float numPeriod = deltaYears/period;
		ellipseBase.phase = OrbitEllipse.MeanToTrueAnomoly(NUtils.DegressMod360( sb.longitude + 360f*numPeriod), ellipseBase.ecc);
	}
    /// <summary>
    /// Determine points from body through closest approach the same distance on the other side
    /// </summary>
    /// <param name="numPoints"></param>
    /// <param name="centerPos"></param>
    /// <param name="startPos"></param>
    /// <returns></returns>
    public Vector3[] OrbitSegmentSymmetricPositions(int numPoints, Vector3 centerPos,
                                                    Vector3 startPos)
    {
        GravityEngine ge = GravityEngine.Instance();

        CalculateRotation();

        // map points into xy plane
        Vector3 start_xy = Quaternion.Inverse(hyper_orientation) * (startPos - centerPos);

        // symmetric around origin
        float start_y = -start_xy.y;
        float end_y   = start_xy.y;

        if (start_y > end_y)
        {
            float temp = start_y;
            start_y = end_y;
            end_y   = temp;
        }

        float dy = Mathf.Abs(end_y - start_y) / (float)numPoints;
        float y  = start_y;
        int   i  = 0;

        Vector3[] points = new Vector3[numPoints];
        while (y < end_y)
        {
            points[i] = PositionForY(y, centerPos);
            if (NUtils.VectorNaN(points[i]))
            {
                Debug.LogError(string.Format("Vector NaN = {0} y={1} ecc={2} ", points[i], y, ecc));
                points[i] = Vector3.zero;
            }
            else if (ge.mapToScene)
            {
                points[i] = ge.MapToScene(points[i]);
            }
            y += dy;
            i++;
            if (i > numPoints - 1)
            {
                break;
            }
        }
        // fill to end with last point
        int last = i - 1;

        if (last < 0)
        {
            last = 0;
        }
        while (i < numPoints)
        {
            points[i++] = points[last];
        }
        return(points);
    }
 public void AngleFromSinCos()
 {
     // check each quadrant
     float[] angles = { 0, 0.3f * Mathf.PI, 0.7f * Mathf.PI, 1.3f * Mathf.PI, 1.7f * Mathf.PI };
     foreach (float angle in angles)
     {
         float a = NUtils.AngleFromSinCos(Mathf.Sin(angle), Mathf.Cos(angle));
         Debug.Log("angle=" + angle + " a=" + a);
         Assert.IsTrue(Mathf.Abs(angle - a) < 1E-2);
     }
 }
 public void Mod360()
 {
     // check each quadrant
     float[] angles = { -90f, 20f, 355f, 270f + 2 * 360f, 14f * 360f + 5f };
     float[] answer = { 270f, 20f, 355f, 270f, 5f };
     for (int i = 0; i < angles.Length; i++)
     {
         float a = NUtils.DegreesMod360(angles[i]);
         Debug.Log("angle=" + angles[i] + " a=" + a);
         Assert.IsTrue(Mathf.Abs(a - answer[i]) < 1E-2);
     }
 }
Beispiel #12
0
    public void PreEvolve(GravityState gravityState, ref byte[] info)
    {
        double[] m = gravityState.m;
        double[,] r = gravityState.r;
        // Precalc initial acceleration
        double[] rji = new double[GravityEngine.NDIM];
        double   r2;
        double   r3;
        double   r_sep;
        double   accel;

        for (int i = 0; i < numBodies; i++)
        {
            for (int k = 0; k < GravityEngine.NDIM; k++)
            {
                a[i, k] = 0.0;
            }
        }
        for (int i = 0; i < numBodies; i++)
        {
            for (int j = i + 1; j < numBodies; j++)
            {
                r2 = 0;
                for (int k = 0; k < GravityEngine.NDIM; k++)
                {
                    rji[k] = r[j, k] - r[i, k];
                    r2    += rji[k] * rji[k];
                }
                if (forceDelegate == null)
                {
                    r3 = r2 * System.Math.Sqrt(r2) + EPSILON;
                    for (int k = 0; k < GravityEngine.NDIM; k++)
                    {
                        a[i, k] += m[j] * rji[k] / r3;
                        a[j, k] -= m[i] * rji[k] / r3;
                    }
                }
                else
                {
                    r_sep = System.Math.Sqrt(r2) + EPSILON;
                    accel = forceDelegate.CalcF(r_sep);
                    for (int k = 0; k < GravityEngine.NDIM; k++)
                    {
                        a[i, k] += m[j] * accel * (rji[k] / r_sep);
                        a[j, k] -= m[i] * accel * (rji[k] / r_sep);
                    }
                }
            }
        }

        initialEnergy = NUtils.GetEnergy(numBodies, ref m, ref r, ref v);
    }
Beispiel #13
0
    public static void SetEllipse(float epoch, EllipseBase ellipseBase, SolarBody sb)
    {
        // orbital element variation is not provided - only phase to determine
        // What is the delta to the reference epoch?
        float deltaYears = epoch - sb.epoch;
        float period     = SolarUtils.GetPeriodYears(sb);
        float numPeriod  = deltaYears / period;

        // epoch was for time at perihelion (i.e. longitude = 0)
        // w = w_bar - Omega,
        ellipseBase.phase = OrbitEllipse.MeanToTrueAnomoly(NUtils.DegressMod360(360f * numPeriod), ellipseBase.ecc);
//		Debug.Log(" numP=" + numPeriod + " M=" + NUtils.DegressMod360(360f*numPeriod) +
//			 " phase=" + ellipseBase.phase);
    }
Beispiel #14
0
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            fromPhase += PHASE_PER_KEY;
        }
        else if (Input.GetKey(KeyCode.S))
        {
            fromPhase -= PHASE_PER_KEY;
        }
        else if (Input.GetKey(KeyCode.Q))
        {
            toPhase += PHASE_PER_KEY;
        }
        else if (Input.GetKey(KeyCode.W))
        {
            toPhase -= PHASE_PER_KEY;
        }
        fromPhase = NUtils.DegreesMod360(fromPhase);
        toPhase   = NUtils.DegreesMod360(toPhase);
        SetMarkers();

        shipOrbitData.SetOrbitForVelocity(spaceshipNBody, shipOrbit.centerNbody);

        // Determine TOF
        Vector3d from = new Vector3d(shipOrbitData.GetPhysicsPositionforEllipse(fromPhase));
        Vector3d to   = new Vector3d(shipOrbitData.GetPhysicsPositionforEllipse(toPhase));

        Vector3d shipPos = GravityEngine.instance.GetPositionDoubleV3(spaceshipNBody);
        double   tPeri   = shipOrbit.TimeOfFlight(shipPos, new Vector3d(shipOrbitData.GetPhysicsPositionforEllipse(0f)));
        double   tApo    = shipOrbit.TimeOfFlight(shipPos, new Vector3d(shipOrbitData.GetPhysicsPositionforEllipse(180f)));
        double   tof     = shipOrbit.TimeOfFlight(from, to);

        // Scale to game time
        //tApo = GravityScaler.ScaleToGameSeconds((float) tApo);
        //tPeri = GravityScaler.ScaleToGameSeconds((float)tPeri);
        //tof = GravityScaler.ScaleToGameSeconds((float)tof);
        //tofText.text = string.Format("Time of Flight = {0:#.#}\nTime to Apoapsis = {1:#.#}\nTime to Periapsis = {2:#.#}\ntau = {3}",
        //    tof, tApo, tPeri, shipOrbitData.tau);
        GravityScaler.Units units = GravityEngine.instance.units;
        tofText.text = string.Format("Time of Flight = {0}\nTime to Apoapsis = {1}\nTime to Periapsis = {2}\ntau = {3}",
                                     GravityScaler.GetWorldTimeFormatted(tof, units),
                                     GravityScaler.GetWorldTimeFormatted(tApo, units),
                                     GravityScaler.GetWorldTimeFormatted(tPeri, units),
                                     GravityScaler.GetWorldTimeFormatted(shipOrbitData.tau, units));
    }
    /// <summary>
    /// Sets the ellipse parameters for planet.
    /// </summary>
    /// <param name="epoch">Epoch.</param>
    /// <param name="ellipseBase">Ellipse base.</param>
    public static void SetEllipse(float epoch, EllipseBase ellipseBase, SolarBody sb)
    {
        // Based on JPL data, apply the per century drift to the orbital parameters
        // T = number of centuries past J2000
        float T = (epoch - 2000f) / 100f;

        ellipseBase.a           = sb.a + sb.a_dot * T;
        ellipseBase.ecc         = sb.ecc + sb.ecc_dot * T;
        ellipseBase.inclination = sb.inclination + sb.inclination_dot * T;
        ellipseBase.omega_uc    = NUtils.DegreesMod360(sb.omega_uc + sb.omega_uc_dot * T);
        // following JPL doc (http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf)
        float current_omega_bar = sb.omega_lc_bar + sb.omega_lc_bar_dot * T;

        ellipseBase.omega_lc = NUtils.DegreesMod360(current_omega_bar - ellipseBase.omega_uc);
        float L            = sb.longitude + sb.longitudeDot * T;
        float mean_anomoly = NUtils.DegreesMod360(L - current_omega_bar);

        ellipseBase.phase = mean_anomoly;
    }
Beispiel #16
0
    /// <summary>
    /// Calculate an array of points that describe the specified orbit
    /// </summary>
    /// <returns>The positions.</returns>
    /// <param name="numPoints">Number points.</param>
    public Vector3[] OrbitPositions(int numPoints)
    {
        Vector3[] emptyArray = { new Vector3(0, 0, 0), new Vector3(0, 0, 0) };
        // need to have a center to create positions.
        if (centerObject == null && transform.parent != null)
        {
            centerObject = transform.parent.gameObject;
        }
        if (centerObject == null)
        {
            return(emptyArray);
        }
        Vector3[] points = new Vector3[numPoints];

        UpdateOrbitParams();
        CalculateRotation();
        // start at theta=0 on the ellipse and transform to world space
        float   r           = a_scaled * (1f - ecc * ecc) / (1f + ecc);
        Vector3 oldPosition = new Vector3(r, 0, 0);

        oldPosition  = ellipse_orientation * oldPosition;
        oldPosition += centerObject.transform.position;

        float dtheta = 2f * Mathf.PI / numPoints;
        float theta  = 0;

        // add a fudge factor to ensure we go all the way around the circle
        for (int i = 0; i < numPoints; i++)
        {
            points[i] = PositionForTheta(theta);
            if (NUtils.VectorNaN(points[i]))
            {
                points[i] = Vector3.zero;
            }
            theta += dtheta;
        }
        // close the path (credit for fix to R. Vincent)
        points[numPoints - 1] = points[0];
        return(points);
    }
    /// <summary>
    /// Use the A/D to position the maneuver symbol on the start orbit.
    /// Use KL to position the symbol on the SOI.
    ///
    /// As move to a new maneuver destination the transfer time will reset to the
    /// minimum energy value. At a given maneuver position, can use W/S to increase/decrease
    /// the transfer time.
    /// </summary>
    private bool UpdateManeuverSymbols()
    {
        bool keyPressed = false;

        // ship
        if (Input.GetKeyDown(KeyCode.K))
        {
            soiAngle = (float)NUtils.AngleMod2Pi(soiAngle + dAngleDegrees * Mathf.Deg2Rad);
            UpdateSoiPosition();
            keyPressed = true;
        }
        else if (Input.GetKeyDown(KeyCode.L))
        {
            soiAngle = (float)NUtils.AngleMod2Pi(soiAngle - dAngleDegrees * Mathf.Deg2Rad);
            UpdateSoiPosition();
            keyPressed = true;
        }
        // update degree values so can see result in inspector
        shipAngleDeg = shipAngle * Mathf.Rad2Deg;
        soiAngleDeg  = soiAngle * Mathf.Rad2Deg;
        return(keyPressed);
    }
 public void PreEvolve(ref double[] mass, ref double[,] pos, ref byte[] info)
 {
     Get_acc_jerk_pot_coll(ref mass, ref pos, ref info);
     initialEnergy = NUtils.GetEnergy(numBodies, ref mass, ref pos, ref vel);
 }
 public float GetEnergy(ref double[] m, ref double[,] r)
 {
     return((float)NUtils.GetEnergy(numBodies, ref m, ref r, ref vel));
 }
Beispiel #20
0
 public float GetEnergy(GravityState gravityState)
 {
     return((float)NUtils.GetEnergy(numBodies, ref gravityState.m, ref gravityState.r, ref v));
 }
    /// <summary>
    /// Called from the GravityEngine on FixedUpdate cycles to determine current position of body given
    /// the physics time evolution only when mode=KEPLERS_EQN.
    ///
    /// This routine updates the game object position in game space and physics space.
    ///
    /// Do not call this method directly.
    /// </summary>
    /// <param name="physicsTime">Physics time.</param>
    /// <param name="physicalScale">Physical scale.</param>
    /// <param name="r">Reference to array into which new position is placed.</param>
    public void Evolve(double physicsTime, ref double[] r_new)
    {
        //  There is no simple expression for the position in an Elliptical orbit as a function of time.
        //	(Expressions exist that describe position as a function of the angle in the orbit, but determining
        //	angle as a function of time results in an expression that is not elementary - Kepler's equation).
        //
        //	Here we follow the excellent development of the equations in "Gravity" (Poisson and Will, 2014).
        //
        // following Gravity (Poisson & Will) Box 3.1
        // 1) First use Newton's root-finding method to determine eccentic anomoly u for a given t
        // The mean anomoly (angle from center of ellipse if motion was circular and uniform) is determined
        // from the orbit period and time evolved so far.
        int loopCount = 0;
        // mean_anomoly is the angle around the circle of radius a if the body moved uniformly
        // (which it does not)
        float mean_anomoly = 2f * Mathf.PI * (float)physicsTime / orbitPeriod;

        mean_anomoly += mean_anomoly_phase;
        float     u          = mean_anomoly; // seed with mean anomoly
        float     u_next     = 0;
        const int LOOP_LIMIT = 20;

        while (loopCount++ < LOOP_LIMIT)
        {
            // this should always converge in a small number of iterations - but be paranoid
            u_next = u + (mean_anomoly - (u - ecc * Mathf.Sin(u))) / (1 - ecc * Mathf.Cos(u));
            if (Mathf.Abs(u_next - u) < 1E-5)
            {
                break;
            }
            u = u_next;
        }
        if (loopCount >= LOOP_LIMIT)
        {
            u_next = u + (mean_anomoly - (u - ecc * Mathf.Sin(u))) / (1 - ecc * Mathf.Cos(u));
            Debug.LogWarning(string.Format("Failed to converge (use best estimate) err={0:E5}", Mathf.Abs(u_next - u)));
            // keep going anyway
        }
        // 2) eccentric anomoly is angle from center of ellipse, not focus (where centerObject is). Convert
        //    to true anomoly, f - the angle measured from the focus. (see Fig 3.2 in Gravity)
        float cos_f = (Mathf.Cos(u) - ecc) / (1f - ecc * Mathf.Cos(u));
        float sin_f = (Mathf.Sqrt(1 - ecc * ecc) * Mathf.Sin(u)) / (1f - ecc * Mathf.Cos(u));
        float r     = a_phy * (1f - ecc * ecc) / (1f + ecc * cos_f);

        position = new Vector3(r * cos_f, r * sin_f, 0);

        // Need a precise (right now) value for centerBody for best results, get from the engine
        // move from XY plane to the orbital plane and scale to world space
        // orbit position is WRT center
        position = ellipse_orientation * position + GravityEngine.Instance().GetPhysicsPosition(centerNbody);
        // fill in r. GE will use this position.
        r_new[0] = position.x;
        r_new[1] = position.y;
        r_new[2] = position.z;

        // determine velocity
        // (C&P from above for performance)
        // Murray and Dermot
        // (2.26)
        // This should really be (M+m), but assume m << M
        // (massScale is added in at the GE level)
        float n = Mathf.Sqrt((float)(centerNbody.mass * GravityEngine.Instance().massScale) / (a_phy * a_phy * a_phy));
        // (2.36)
        float   denom = Mathf.Sqrt(1f - ecc * ecc);
        float   xdot  = -1f * n * a_phy * sin_f / denom;
        float   ydot  = n * a_phy * (ecc + cos_f) / denom;
        Vector3 v_xy  = new Vector3(xdot, ydot, 0);

        velocityScaled = ellipse_orientation * v_xy + GravityEngine.Instance().GetScaledVelocity(centerNbody);
        phase          = NUtils.AngleFromSinCos(sin_f, cos_f) * Mathf.Rad2Deg;
    }
Beispiel #22
0
    private void HyperOrbitForVelocity(NBody forNbody, NBody aroundNBody)
    {
        // Murray and Dermott Ch2.8 (2.134) - (2.140)
        float velSq = forNbody.vel_scaled.sqrMagnitude;

        Vector3 r_vec = forNbody.transform.position - aroundNBody.transform.position;
        float   r     = Vector3.Magnitude(r_vec);

        r_initial = r;
        float mu = aroundNBody.mass;

        // semi-major axis (2.134)
        // (reversed for HB)
        a = 1f / (velSq / mu - 2 / r);

        // Determine angular momentum, h
        Vector3 h_vec = Vector3.Cross(r_vec, forNbody.vel_scaled);
        float   h     = Vector3.Magnitude(h_vec);

        //Debug.Log("h_vec = " + h_vec + " r_vec=" + r_vec + " v=" + forNbody.vel + " planet pos=" + forNbody.transform.position);

        // eccentricity (2.135)
        ecc        = Mathf.Sqrt(h * h / (mu * a) + 1f);
        perihelion = a * (ecc - 1);

        // inclination (0..180 so Acos is unambiguous) (2.136)
        float inclRad = Mathf.Acos(h_vec.z / h);

        // Omega_uc - only relevant if there is non-zero inclination
        float omega_ucRad  = 0f;
        float sinOmega     = 0f;
        float cosOmega     = 1f;
        bool  inclNoneZero = Mathf.Abs(Mathf.Sin(inclRad)) > 1E-5;

        if (inclNoneZero)
        {
            sinOmega = h_vec.x / (h * Mathf.Sin(inclRad));
            cosOmega = -h_vec.y / (h * Mathf.Sin(inclRad));
        }
        else if (h_vec.z < 0)
        {
            // if incl = 180
            sinOmega *= -1f;
            cosOmega *= -1f;
        }
        omega_ucRad = NUtils.AngleFromSinCos(sinOmega, cosOmega);
//		Debug.Log("sinOmega=" + sinOmega + " cosOmega=" + cosOmega + " omega_ucRad=" + omega_ucRad + " inclRad=" + inclRad
//			+ " inclNonZero=" + inclNoneZero + " h_vec=" + h_vec);

        float f = 0;

        if (ecc > 1E-3)
        {
            // Like M&D 2.31 but for e^2-1 not 1-e^2
            float rdot = Mathf.Sqrt(velSq - h * h / (r * r));
            if (Vector3.Dot(r_vec, forNbody.vel_scaled) < 0)
            {
                rdot *= -1f;
            }
            float cos_f = (1 / ecc) * (a * (ecc * ecc - 1) / r - 1f);
            float sin_f = rdot * a * (ecc * ecc - 1f) / (h * ecc);
            f = NUtils.AngleFromSinCos(sin_f, cos_f);
        }

        // (2.6.17)
        // sin(w+f) = Z/(r sin(i))
        // cos(w+f) = [X cos(Omega) + Y sin(Omega)]/r
        // when sin(i) = 0, will have Z=0 and w + f = 0
        float sin_of      = 0f;
        float cos_of      = 1f;
        float omega_lcRad = 0f;

        if (inclNoneZero)
        {
            sin_of      = r_vec.z / (r * Mathf.Sin(inclRad));
            cos_of      = (r_vec.x * cosOmega + r_vec.y * sinOmega) / r;
            omega_lcRad = (NUtils.AngleFromSinCos(sin_of, cos_of) - f);
        }
        else
        {
            float sin_theta = r_vec.y / r;
            float cos_theta = r_vec.x / r;
            float theta     = NUtils.AngleFromSinCos(sin_theta, cos_theta);
//			Debug.Log("r_vec=" + r_vec + " theta=" + theta + " f=" + f + " (theta - f)=" + (theta-f));
            if (inclRad < Mathf.PI / 2f)
            {
                omega_lcRad = theta - f;
            }
            else
            {
                if (h_vec.z > 0)
                {
                    omega_ucRad = f - theta;
                }
                else
                {
                    // Rotated by 180 around x, so flip sign of y
                    sin_theta   = -r_vec.y / r;
                    cos_theta   = r_vec.x / r;
                    theta       = NUtils.AngleFromSinCos(sin_theta, cos_theta);
                    omega_ucRad = f - theta;
                }
            }
        }
        // Ellipse wants degrees
        omega_lc = Mathf.Rad2Deg * omega_lcRad;
        if (omega_lc < 0)
        {
            omega_lc += 360f;
        }
        omega_uc = Mathf.Rad2Deg * omega_ucRad;
        if (omega_uc < 0)
        {
            omega_uc += 360f;
        }
        phase       = Mathf.Rad2Deg * f;
        inclination = Mathf.Rad2Deg * inclRad;
//		Debug.Log("cosof=" + cos_of + " sinof=" + sin_of + " of=" + NUtils.AngleFromSinCos(sin_of, cos_of) + " f=" + f);
    }
    /// <summary>
    /// Generate the points for an orbit segment given the start and end positions. If shortPath then
    /// the short path between the points will be shown, otherwise the long way around.
    ///
    /// The points are used to determine an angle from the main axis of the ellipse and although they
    /// should be on the ellipse for best results, the code will do it's best if they are not.
    /// </summary>
    /// <param name="numPoints"></param>
    /// <param name="centerPos"></param>
    /// <param name="startPos"></param>
    /// <param name="endPos"></param>
    /// <param name="shortPath"></param>
    /// <returns></returns>
    public Vector3[] OrbitSegmentPositions(int numPoints,
                                           Vector3 centerPos,
                                           Vector3 startPos,
                                           Vector3 endPos,
                                           bool shortPath)
    {
        GravityEngine ge = GravityEngine.Instance();

        Vector3[] points = new Vector3[numPoints];

        UpdateOrbitParams();
        CalculateRotation();

        float dtheta = 2f * Mathf.PI / numPoints;
        float theta  = 0;

        // find the vector to theta=0 on the ellipse, with no offset
        Vector3 ellipseAxis = PositionForTheta(0f, Vector3.zero);
        Vector3 normal      = ellipse_orientation * Vector3.forward;
        float   theta1      = NUtils.AngleFullCircleRadians(ellipseAxis, startPos - centerPos, normal);
        float   theta2      = NUtils.AngleFullCircleRadians(ellipseAxis, endPos - centerPos, normal);

        if (inclination > 90)
        {
            float temp = theta1;
            theta1 = theta2;
            theta2 = temp;
        }
        if (theta1 > theta2)
        {
            float temp = theta1;
            theta1 = theta2;
            theta2 = temp;
        }
        if (!shortPath)
        {
            float temp = theta1;
            theta1 = theta2;
            // ok to go beyond 2 Pi, since will increment to theta2
            theta2 = temp + 2f * Mathf.PI;
        }
        // Debug.LogFormat("theta1={0} theta2={1} start={2} end={3} axis={4}", theta1, theta2, startPos, endPos, ellipseAxis);

        int i = 0;

        for (theta = theta1; theta < theta2; theta += dtheta)
        {
            points[i] = PositionForTheta(theta, centerPos);
            if (NUtils.VectorNaN(points[i]))
            {
                Debug.LogError("Vector NaN + " + points[i]);
                points[i] = Vector3.zero;
            }
            else if (ge.mapToScene)
            {
                points[i] = ge.MapToScene(points[i]);
            }
            i++;
            if (i > numPoints - 1)
            {
                break;
            }
        }
        // fill to end with last point
        int last = i - 1;

        if (last < 0)
        {
            last = 0;
        }
        while (i < numPoints)
        {
            points[i++] = points[last];
        }

        return(points);
    }
Beispiel #24
0
    private void EllipseOrbitForVelocity(NBody forNbody, NBody aroundNBody)
    {
        // Murray and Dermott Ch2.8 (2.134) - (2.140)
        Vector3 vel   = forNbody.vel_scaled - aroundNBody.vel_scaled;
        float   velSq = vel.sqrMagnitude;

        Vector3 r_vec = forNbody.transform.position - aroundNBody.transform.position;
        float   r     = Vector3.Magnitude(r_vec);
        float   mu    = aroundNBody.mass;

        // semi-major axis (2.134)
        a = 1f / (2 / r - velSq / mu);

        // Determine angular momentum, h
        Vector3 h_vec = Vector3.Cross(r_vec, forNbody.vel_scaled);
        float   h     = Vector3.Magnitude(h_vec);
        //Debug.Log("h_vec = " + h_vec + " r_vec=" + r_vec + " v=" + forNbody.vel + " planet pos=" + forNbody.transform.position);

        // eccentricity (2.135)
        float eqn1 = h * h / (mu * a);

        if (eqn1 > 1f)
        {
            // Can be slightly bigger than 1 due to numerical error
            ecc = 0f;
        }
        else
        {
            ecc = Mathf.Sqrt(1f - eqn1);
        }

        // inclination (0..180 so Acos is unambiguous) (2.136)
        float inclRad = Mathf.Acos(h_vec.z / h);

        // Omega_uc - only relevant if there is non-zero inclination
        float omega_ucRad  = 0f;
        float sinOmega     = 0f;
        float cosOmega     = 1f;
        bool  inclNoneZero = Mathf.Abs(Mathf.Sin(inclRad)) > 1E-5;

        if (inclNoneZero)
        {
            sinOmega = h_vec.x / (h * Mathf.Sin(inclRad));
            cosOmega = -h_vec.y / (h * Mathf.Sin(inclRad));
        }
        else if (h_vec.z < 0)
        {
            // if incl = 180
            sinOmega *= -1f;
            cosOmega *= -1f;
        }
        omega_ucRad = NUtils.AngleFromSinCos(sinOmega, cosOmega);
//		Debug.Log("sinOmega=" + sinOmega + " cosOmega=" + cosOmega + " omega_ucRad=" + omega_ucRad + " inclRad=" + inclRad
//			+ " inclNonZero=" + inclNoneZero + " h_vec=" + h_vec);

        float f = 0;

        if (ecc > 1E-3)
        {
            // Ellipse (from Sidi)
            float cosPhi = (a - r) / (a * ecc);
            float sinPhi = Vector3.Dot(r_vec, forNbody.vel_scaled) / (ecc * Mathf.Sqrt(mu * a));
            float cosf   = (cosPhi - ecc) / (1 - ecc * cosPhi);
            float sinf   = sinPhi * Mathf.Sqrt(1 - ecc * ecc) / (1 - ecc * cosPhi);
            f = NUtils.AngleFromSinCos(sinf, cosf);
        }

        // (2.6.17)
        // sin(w+f) = Z/(r sin(i))
        // cos(w+f) = [X cos(Omega) + Y sin(Omega)]/r
        // when sin(i) = 0, will have Z=0 and w + f = 0
        float sin_of      = 0f;
        float cos_of      = 1f;
        float omega_lcRad = 0f;

        if (inclNoneZero)
        {
            sin_of      = r_vec.z / (r * Mathf.Sin(inclRad));
            cos_of      = (r_vec.x * cosOmega + r_vec.y * sinOmega) / r;
            omega_lcRad = (NUtils.AngleFromSinCos(sin_of, cos_of) - f);
        }
        else
        {
            float sin_theta = r_vec.y / r;
            float cos_theta = r_vec.x / r;
            float theta     = NUtils.AngleFromSinCos(sin_theta, cos_theta);
            if (inclRad < Mathf.PI / 2f)
            {
                omega_lcRad = theta - f;
            }
            else
            {
                if (h_vec.z > 0)
                {
                    omega_ucRad = f - theta;
                }
                else
                {
                    // Rotated by 180 around x, so flip sign of y
                    sin_theta   = -r_vec.y / r;
                    cos_theta   = r_vec.x / r;
                    theta       = NUtils.AngleFromSinCos(sin_theta, cos_theta);
                    omega_ucRad = f - theta;
                }
            }
        }
        // Ellipse wants degrees
        omega_lc = Mathf.Rad2Deg * omega_lcRad;
        if (omega_lc < 0)
        {
            omega_lc += 360f;
        }
        omega_uc = Mathf.Rad2Deg * omega_ucRad;
        if (omega_uc < 0)
        {
            omega_uc += 360f;
        }
        phase       = Mathf.Rad2Deg * f;
        inclination = Mathf.Rad2Deg * inclRad;
//		Debug.Log("cosof=" + cos_of + " sinof=" + sin_of + " of=" + NUtils.AngleFromSinCos(sin_of, cos_of) + " f=" + f);

        // Determine time to periapsis (2.140)
        // Eqn assumes E=0 when t=tau
        float E = Mathf.Acos((1f - r / a) / ecc);

        // this equation has a G but we set G=1
        period = 2 * Mathf.PI * Mathf.Sqrt(a * a * a) / Mathf.Sqrt(aroundNBody.mass);
        float M   = (E - ecc * Mathf.Sin(E));
        float tau = M * Mathf.Sqrt(a * a * a) / Mathf.Sqrt(aroundNBody.mass);
        // tau is giving time to/from apoapsis, need to find out which
        float vdotr = Vector3.Dot(vel, r_vec);

        if (vdotr > 0)
        {
            tau = period - tau;
        }
    }