コード例 #1
0
    private float CalcPeriod(float a, NBody centerMass)
    {
        // this equation has a G but we set G=1
        float _period = 2f * Mathf.PI * Mathf.Sqrt(a * a * a) / Mathf.Sqrt(centerMass.mass);

        return(GravityScaler.ScalePeriod(_period));;
    }
コード例 #2
0
 private void UpdateSoiPosition()
 {
     targetPoint = new Vector3d(soiRadius * Mathf.Cos(soiAngle) + moonRadius,
                                soiRadius * Mathf.Sin(soiAngle),
                                0);
     targetPoint = GravityScaler.ScaleVector3dPhyToScene(targetPoint);
 }
コード例 #3
0
    void Awake()
    {
        // Convert from real world units
        // Rocket engine thrust is given in SI units, so acceleration is in SI units
        // For Orbital scale need to convert to km/hr^2
        accelerationConversion = GravityScaler.AccelSItoGEUnits();
        // and convert to the physics scale used in the engine
        accelerationConversion = accelerationConversion * GravityScaler.AccelGEtoInternalUnits();

        burnStart     = new double[MAX_STAGES];
        burnRateScale = GravityScaler.GetGameSecondPerPhysicsSecond();

        fuelLevel = new double[MAX_STAGES];
        for (int i = 0; i < numStages; i++)
        {
            fuelLevel[i] = massFuel[i];
        }

        // acceleration will be opposite to thrust direction
        accelDirection = -thrustAxis;
        activeStage    = 0;

        activeState = GravityEngine.Instance().GetWorldState();

        SetEngine(engineOn);
    }
コード例 #4
0
 private void UpdateStartPosition()
 {
     startPoint = new Vector3d(shipRadius * Mathf.Cos(shipAngle),
                               shipRadius * Mathf.Sin(shipAngle),
                               0);
     startPoint = GravityScaler.ScaleVector3dPhyToScene(startPoint);
 }
コード例 #5
0
    /// <summary>
    /// Callback to compute the launch transfer times and display them in the scene.
    /// </summary>
    public void Compute()
    {
        int       itemNo    = destDropdown.value;
        NBody     toNbody   = destinations[itemNo].GetComponent <NBody>();
        OrbitData fromOrbit = new OrbitData();

        fromOrbit.SetOrbit(fromNbody, centerNbody);
        OrbitData toOrbit = new OrbitData();

        toOrbit.SetOrbit(toNbody, centerNbody);

        HohmannXfer hohmannXfer = new HohmannXfer(fromOrbit, toOrbit, true);

        // Find launch windows
        double[] times = hohmannXfer.LaunchTimes(numWindows);
        List <Dropdown.OptionData> items = new List <Dropdown.OptionData>();

        foreach (double t in times)
        {
            Dropdown.OptionData item = new Dropdown.OptionData();
            item.text = GravityScaler.GetWorldTimeFormatted(t, GravityScaler.Units.SOLAR);
            items.Add(item);
        }
        launchTimes.ClearOptions();
        launchTimes.AddOptions(items);
    }
コード例 #6
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;
        BinaryPair bPair    = (BinaryPair)target;
        Vector3    velocity = Vector3.zero;

        GravityScaler.Units units = GravityEngine.Instance().units;
        string prompt             = string.Format("Velocity ({0})", GravityScaler.VelocityUnits(units));

        velocity = EditorGUILayout.Vector3Field(new GUIContent(prompt, "velocity of binary center of mass"), bPair.velocity);


        if (GUI.changed)
        {
            Undo.RecordObject(bPair, "EllipseBase Change");
            bPair.velocity = velocity;
            EditorUtility.SetDirty(bPair);
        }
        base.OnInspectorGUI();

        if (axisUpdated)
        {
            bPair.ApplyScale(GravityEngine.Instance().GetLengthScale());
        }
    }
コード例 #7
0
    void Update()
    {
        // space toggles evolution
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GravityEngine.Instance().SetEvolve(!GravityEngine.Instance().GetEvolve());
        }
        DateTime newTime = SolarUtils.DateForEpoch(solarSystem.GetStartEpochTime());

        newTime += GravityScaler.GetTimeSpan(GravityEngine.Instance().GetPhysicalTimeDouble(), GravityScaler.Units.SOLAR);
        //currentTime.text =  newTime.ToString("yyyy:MM:dd"); // 24h format
        //currentTime.text = newTime.ToString("yyyy:MM:dd HH:mm:ss");
        CurrentDate.SetText(newTime.ToString("yyyy:MM:dd HH:mm:ss"));
        CurrentDateHighlighted.SetText(newTime.ToString("yyyy:MM:dd HH:mm:ss"));

        // ICK! Need to wait until GE moves these objects before can clear the trail
        if (clearTrail)
        {
            if (clearTrailDelay-- <= 0)
            {
                ResetTrails();
                clearTrail = false;
            }
        }
    }
コード例 #8
0
    // Use this for initialization (must Awake, since start of GameLoop will set states)
    void Awake()
    {
        state      = State.SELECT_OBJECTIVE;
        intercepts = null;

        time_to_moon_phys = TIME_TO_MOON_SEC / GravityScaler.GetGameSecondPerPhysicsSecond();

        if (targets.Length == 0)
        {
            Debug.LogError("No targets configured");
        }
        // Player is spaceship 1, others are objectives

        // take first ship to tbe the player
        target = targets[0];


        // Need to configure objective chooser
        SetObjectiveOptions(targets);

        SetState(state);

        // add a trajectory intercepts component (it need to handle markers so it has
        // a monobehaviour base class).
        // The pair of spaceships to be checked will be selected dynamically
        trajIntercepts = gameObject.AddComponent <TrajectoryIntercepts>();
        trajIntercepts.interceptSymbol  = interceptMarker;
        trajIntercepts.rendezvousSymbol = rendezvousMarker;

        spaceshipGO = spaceshipCtrl.transform.parent.gameObject;
        // optional
        spaceshipOrbit = spaceshipGO.GetComponent <OrbitUniversal>();

        // only record the elements that are active at the start of the scene
        orbitPredictors = new List <OrbitPredictor>();
        foreach (OrbitPredictor op in  (OrbitPredictor[])Object.FindObjectsOfType(typeof(OrbitPredictor)))
        {
            if (op.gameObject.activeInHierarchy)
            {
                orbitPredictors.Add(op);
                if (op.transform.parent == spaceshipGO.transform)
                {
                    shipOrbitPredictor = op;
                }
            }
        }
        if (shipOrbitPredictor == null)
        {
            Debug.LogError("Did not find orbit predictor for ship");
        }

        orbitRenderers = new List <OrbitRenderer>();
        foreach (OrbitRenderer or in (OrbitRenderer[])Object.FindObjectsOfType(typeof(OrbitRenderer)))
        {
            if (or.gameObject.activeInHierarchy)
            {
                orbitRenderers.Add(or);
            }
        }
    }
コード例 #9
0
    // Update is called once per frame
    void Update()
    {
        if (!frame1Hack)
        {
            frame1Hack = true;
            AddGhostBodies();
            ComputeBaseTransferTime();
            // need GE to process these updates
            Debug.LogFormat("Moon period={0:0.0}", ghostMoonOrbit[MOON_SOI_ENTER].GetPeriod());
        }

        if (!running)
        {
            // Getting user input for FR
            AdjustTimeOfFlight();
            UpdateManeuverSymbols();
            HandleMouseSOIInput();
            ComputeTransfer();
            if (freeReturnInfo != null)
            {
                freeReturnInfo.text = string.Format("Perilune = {0:0.0}\nReturn Perigee={1:0.0}\nTime to SOI = {2:0.0}\n{3}",
                                                    ghostShipOrbit[SOI_HYPER].GetPerigee(),
                                                    ghostShipOrbit[EXIT_SOI].GetPerigee(),
                                                    timeHohmann * tflightFactor,
                                                    GravityScaler.GetWorldTimeFormatted(timeHohmann * tflightFactor, ge.units));
            }
        }
        else
        {
            // RUNNING
            if (Input.GetKeyUp(KeyCode.C))
            {
                // Circularize (if in the vicinity of the moon)
                CircularizeAroundMoon();
            }
            else if (Input.GetKeyUp(KeyCode.R))
            {
                // Raise circular orbit but Hohmann Xfer
                NewCircularOrbit(1.3f);
            }
            return;
        }


        if (Input.GetKeyUp(KeyCode.X))
        {
            // execute the transfer
            ExecuteTransfer();
            if (instructions != null)
            {
                instructions.gameObject.SetActive(false);
            }
            running = true;
        }
        else if (Input.GetKeyUp(KeyCode.Space))
        {
            ge.SetEvolve(!ge.GetEvolve());
        }
    }
コード例 #10
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;

        GravityParticles nbp              = (GravityParticles)target;
        Vector3          initialV         = nbp.initialVelocity;
        bool             addNBodyVelocity = nbp.addNBodyVelocity;

        IGravityParticlesInit particlesInit = nbp.GetComponent <IGravityParticlesInit>();

        GravityScaler.Units units = GravityEngine.Instance().units;
        string prompt             = string.Format("Initial Vel. ({0})", GravityScaler.VelocityUnits(units));

        if (particlesInit == null)
        {
            EditorGUILayout.LabelField("No init script", EditorStyles.boldLabel);
            bool hasNBody = false;
            if (nbp.GetComponent <NBody>() != null)
            {
                hasNBody = true;
            }
            else if (nbp.transform.parent != null && nbp.transform.parent.gameObject.GetComponent <NBody>() != null)
            {
                hasNBody = true;
            }
            if (hasNBody)
            {
                addNBodyVelocity = EditorGUILayout.Toggle(new GUIContent("Use velocity from NBody", velTip), nbp.addNBodyVelocity);
                if (addNBodyVelocity)
                {
                    EditorGUILayout.LabelField("Initial Velocity: (from NBody)", EditorStyles.boldLabel);
                }
                else
                {
                    initialV = EditorGUILayout.Vector3Field(new GUIContent(prompt, iTip), nbp.initialVelocity);
                }
            }
            else
            {
                initialV = EditorGUILayout.Vector3Field(new GUIContent(prompt, iTip), nbp.initialVelocity);
            }
        }
        else
        {
            EditorGUILayout.LabelField("Initalize with: " + particlesInit.GetType().ToString(), EditorStyles.boldLabel);
        }

        if (GUI.changed)
        {
            Undo.RecordObject(nbp, "GravityParticles Change");
            nbp.initialVelocity  = initialV;
            nbp.addNBodyVelocity = addNBodyVelocity;
            EditorUtility.SetDirty(nbp);
        }
    }
コード例 #11
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;

        NBodyCollision nbc        = (NBodyCollision)target;
        GameObject     explodePF  = nbc.explosionPrefab;
        int            precedence = nbc.collisionPrecedence;
        float          explodeOrBounceVelocity = nbc.explodeOrBounceVelocity;
        float          bounceFactor            = 1f;
        string         layer = null;

        float oldWidth = EditorGUIUtility.labelWidth;

        EditorGUIUtility.labelWidth = 200;

        NBodyCollision.CollisionType type = NBodyCollision.CollisionType.ABSORB_IMMEDIATE;

        type       = (NBodyCollision.CollisionType)EditorGUILayout.EnumPopup(new GUIContent("Collision Type", collTip), nbc.collisionType);
        precedence = EditorGUILayout.IntField(new GUIContent("Collision Precedence", cTip), nbc.collisionPrecedence);

        layer = EditorGUILayout.TextField(new GUIContent("Collision Layer (Optional)", layerTip), nbc.collisionLayer);

        if (type == NBodyCollision.CollisionType.EXPLODE)
        {
            explodePF = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("Explosion Prefab", "Particle System with NBodyParticles"), explodePF, typeof(GameObject), true);
        }
        else if (type == NBodyCollision.CollisionType.BOUNCE)
        {
            EditorGUIUtility.labelWidth = oldWidth;
            bounceFactor = EditorGUILayout.Slider(new GUIContent("Bounce", bTip), nbc.bounceFactor, 0f, 1f);
        }
        else if (type == NBodyCollision.CollisionType.EXPLODE_OR_BOUNCE)
        {
            explodePF = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("Explosion Prefab", "Particle System with NBodyParticles"), explodePF, typeof(GameObject), true);
            bounceFactor = EditorGUILayout.Slider(new GUIContent("Bounce", bTip), nbc.bounceFactor, 0f, 1f);
            GravityScaler.Units units = GravityEngine.Instance().units;
            EditorGUIUtility.labelWidth = oldWidth;
            string prompt = string.Format("Relative Velocity to Explode ({0})", GravityScaler.VelocityUnits(units));
            explodeOrBounceVelocity = EditorGUILayout.FloatField(new GUIContent(prompt, dTip), nbc.explodeOrBounceVelocity);
        }
        if (GUI.changed)
        {
            Undo.RecordObject(nbc, "NBodyCollision Change");
            nbc.explosionPrefab         = explodePF;
            nbc.collisionType           = type;
            nbc.bounceFactor            = bounceFactor;
            nbc.explodeOrBounceVelocity = explodeOrBounceVelocity;
            nbc.collisionPrecedence     = precedence;
            nbc.collisionLayer          = layer;
            EditorUtility.SetDirty(nbc);
        }
    }
コード例 #12
0
 private void DoTranslation(Vector3 axis)
 {
     if (rigidBodyEnabled)
     {
         rigidBody.AddRelativeForce(deltaV * axis, ForceMode.VelocityChange);
     }
     else
     {
         // for a massless (wrt e.g. Earth) ship, applyimpulse will just do a change in velocity
         ge.ApplyImpulse(nbody, GravityScaler.ScaleVelSceneToPhys(deltaV * axis));
     }
 }
コード例 #13
0
    // Check can go through phys time and still get a sensible DateTime (same day)
    public void SolarTimeNow()
    {
        SolarSystem solar = GameObject.Find("SolarSystem").GetComponent <SolarSystem>();

        Assert.That(solar != null, "Could not get Solar system. Did you open SolarUnitTest scene?");

        System.DateTime newTime = SolarUtils.DateForEpoch(solar.GetStartEpochTime());
        newTime += GravityScaler.GetTimeSpan(GravityEngine.Instance().GetPhysicalTimeDouble(), GravityScaler.Units.SOLAR);
        Assert.AreEqual(newTime.Year, 2016);
        Assert.AreEqual(newTime.Month, 1);
        Assert.AreEqual(newTime.Day, 1);
    }
コード例 #14
0
    void Start()
    {
        SetEngine(engineOn);
        // Convert from real world units
        // Rocket engine thrust is given in SI units, so acceleration is in SI units
        // For Orbital scale need to convert to km/hr^2
        accelerationConversion = GravityScaler.AccelSItoGEUnits();
        // and convert to the physics scale used in the engine
        accelerationConversion = accelerationConversion * GravityScaler.AccelGEtoInternalUnits();

        burnRateScaled  = burnRate * GravityScaler.GetGameSecondPerPhysicsSecond();
        thrustDirection = thrustAxis;
    }
コード例 #15
0
    /// <summary>
    /// Calculate velocity for binary members and assign.
    /// reflect: One of the bodies positions and velocities must be reflected to opposite side of ellipse
    /// </summary>
    private void SetupBody(NBody nbody, float a_n, float mu, bool reflect)
    {
        float a_phy = a_n / GravityEngine.instance.physToWorldFactor;
        // Phase is TRUE anomoly f
        float f            = phase * Mathf.Deg2Rad;
        float reflect_in_y = 1f;

        if (reflect)
        {
            reflect_in_y = -1f;
            //f = f + Mathf.PI;
        }

        // Murray and Dermott (2.20)
        float r = a_phy * (1f - ecc * ecc) / (1f + ecc * Mathf.Cos(f));
        // (2.26) mu = n^2 a^3  (n is period, aka T)
        float n = Mathf.Sqrt(mu * GravityEngine.Instance().massScale / (a_phy * a_phy * a_phy));
        // (2.36)
        float denom = Mathf.Sqrt(1f - ecc * ecc);
        float xdot  = -1f * n * a_phy * Mathf.Sin(f) / denom;
        float ydot  = n * a_phy * (ecc + Mathf.Cos(f)) / denom;

        Vector3 position_xy = new Vector3(reflect_in_y * r * Mathf.Cos(f), r * Mathf.Sin(f), 0);
        // move from XY plane to the orbital plane and scale to world space
        // orbit position is WRT center
        Vector3 position = ellipse_orientation * position_xy;

        // ISSUE: Problematic in case where added after the fact
        position += cmPosition;
        nbody.initialPhysPosition = position;

        Vector3 v_xy = new Vector3(xdot, ydot, 0);

        v_xy *= reflect_in_y;
        // velocity will be scaled when NBody is scaled
        Vector3 vel_phys = Vector3.zero;

        if (binaryNbody != null)
        {
            // use CM velocity from parent for e.g. binary in orbit around something
            vel_phys = binaryNbody.vel_phys;
        }
        else
        {
            vel_phys = velocity * GravityScaler.GetVelocityScale();
        }
        nbody.vel_phys = ellipse_orientation * v_xy + vel_phys;
    }
コード例 #16
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));
    }
コード例 #17
0
    private static void GetMajorAxis(OrbitUniversal orbitU, ref double p_inspector, ref bool sizeUpdate, GravityScaler.Units units)
    {
        float oldLabelWidth = EditorGUIUtility.labelWidth;

        EditorGUIUtility.labelWidth = oldLabelWidth + 50f;
        string prompt = string.Format("Semi-Major Axis (a) [{0}]", GravityScaler.LengthUnits(units));
        double old_a  = orbitU.GetMajorAxisInspector();
        double a      = EditorGUILayout.DelayedDoubleField(new GUIContent(prompt, aTip), old_a);

        if (!EditorApplication.isPlaying && (a != old_a))
        {
            orbitU.SetMajorAxisInspector(a);
            sizeUpdate = true;
            // Need to update ecc and p with new values
            p_inspector = orbitU.p_inspector;
        }
        EditorGUILayout.LabelField(string.Format("Axis result in:  p={0:0.00}", p_inspector));
        EditorGUIUtility.labelWidth = oldLabelWidth;
    }
コード例 #18
0
    //*****************************************************************
    // Run-time methods
    //*****************************************************************

    /// <summary>
    /// Run-time update of the solar system time. The new time must be a time later
    /// than the initial start time of the solar system.
    ///
    /// This API makes use of @GravityEngine#SetPhysicalTime. This requires that ALL
    /// objects in the scene be "on-rails" i.e. have an OrbitXXX component and be in Kepler
    /// evolution mode.
    ///
    /// </summary>
    /// <param name="year"></param>
    /// <param name="month"></param>
    /// <param name="day"></param>
    /// <param name="dayFrac"></param>
    public void SetTime(int year, int month, int day, float dayFrac)
    {
        // TODO - use dayFrac

        // C# DateTime/TimeSpan to find the number of seconds to add
        System.DateTime newTime       = new System.DateTime(year, month, day);
        System.DateTime startTime     = SolarUtils.DateForEpoch(_epochTime);
        double          secsFromStart = (newTime - startTime).Ticks / (1E7);

        if (secsFromStart < 0)
        {
            Debug.LogError("Cannot evolve earlier than solar system start time.");
        }
        Debug.LogFormat("Secs from start={0} phys={1} newPhys={2}",
                        secsFromStart,
                        GravityEngine.Instance().GetPhysicalTimeDouble(),
                        GravityScaler.WorldSecsToPhysTime(secsFromStart));
        GravityEngine.Instance().SetPhysicalTime(GravityScaler.WorldSecsToPhysTime(secsFromStart));
    }
コード例 #19
0
    /// <summary>
    /// Validation:
    /// - confirmed velocity in SI units matches expected orbital velocity of ISS
    /// - checked that SI acceleration = -g at terminal velocity (9.73 m/s^2 at 28 km)
    /// </summary>

    // Use this for initialization
    void Start()
    {
        if (inertialMassKg == 0)
        {
            Debug.LogError("Mass is zero. Drag calculation will fail.");
        }
        if (spaceship == null)
        {
            spaceship = GetComponent <NBody>();
        }

        geDistanceToKm = 1;
        v_ship         = new double[] { 0, 0, 0 };
        v_earth        = new double[] { 0, 0, 0 };

        velocityScaleInternalToSI = GravityScaler.VelocityScaletoSIUnits() / GravityScaler.GetVelocityScale();
        accelSItoGE = GravityScaler.AccelSItoGEUnits() / GravityScaler.AccelerationScaleInternalToGEUnits();

        LoadDensityProfile();

        liveState = GravityEngine.Instance().GetWorldState();
    }
コード例 #20
0
    private void Deactivate()
    {
        // Get CM object pos & vel from GE
        GravityEngine ge    = GravityEngine.Instance();
        Vector3d      cmPos = ge.GetPositionDoubleV3(cmNbody);
        Vector3d      cmVel = ge.GetVelocityDoubleV3(cmNbody);

        int i = 0;

        foreach (NBody nbody in nbodies)
        {
            Rigidbody rb = nbody.GetComponentInChildren <Rigidbody>();
            if (rb == null)
            {
                Debug.LogWarning("could not find rigidbody for  " + nbody.gameObject.name);
                continue;
            }
            // rb.isKinematic = true;
            // set position and velocity
            Vector3d nbodyVel = new Vector3d(GravityScaler.ScaleVelSceneToPhys(rb.velocity));
            ge.SetVelocityDoubleV3(nbody, cmVel + nbodyVel);
            Vector3d nbodyPos = new Vector3d(GravityScaler.ScalePositionSceneToPhys(nbody.transform.localPosition));
            ge.SetPositionDoubleV3(nbody, cmPos + nbodyPos);
            ge.ActivateBody(nbody.gameObject);
            // restore parent
            nbody.transform.parent = priorParents[i];
            i++;
        }
        ge.RemoveBody(cmObject);
        Destroy(cmObject);
        // de-activate any RCS elements
        foreach (ReactionControlSystem r in rcs)
        {
            if (r != null)
            {
                r.SetRigidBodyEnabled(false);
            }
        }
    }
コード例 #21
0
    public void InitFromOrbitData(OrbitData od)
    {
        // a is inited from perihilion
        perihelion_phys = od.perihelion;
        // @TODO: This should be in selected units!
        perihelion  = GravityScaler.ScaleDistancePhyToScene(od.perihelion);
        ecc         = od.ecc;
        omega_lc    = od.omega_lc;
        omega_uc    = od.omega_uc;
        inclination = od.inclination;
        phase_nu    = od.phase * Mathf.Deg2Rad;
        // normally a should be negative, but we made it positive...
        p = od.a * (1 - ecc * ecc);
        //
        float   denom = 1 + ecc * Mathf.Cos(phase_nu);
        Vector3 r_pqw = new Vector3(p * Mathf.Cos(phase_nu) / denom, p * Mathf.Sin(phase_nu) / denom, 0);

        r_initial_phy = r_pqw.magnitude;

        initFromOrbitData = true;
        Init();
        PreEvolve(GravityEngine.Instance().physToWorldFactor, GravityEngine.Instance().massScale);
    }
コード例 #22
0
ファイル: DrawSOI.cs プロジェクト: AlekseiBespalov/AstrocomV2
    /// <summary>
    ///  Draw a circle at SOI radius around the moon
    /// </summary>
    /// <param name="physRadius">radius in physics units</param>
    private void Draw(float physRadius)
    {
        const int numPoints = 200;

        Vector3[] points = new Vector3[numPoints];

        float radius = GravityScaler.ScaleDistancePhyToScene(physRadius);

        float dtheta = 2f * Mathf.PI / (float)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]  = new Vector3(radius * Mathf.Cos(theta), radius * Mathf.Sin(theta), 0);
            points[i]  = Quaternion.AngleAxis(inclination, Vector3.right) * points[i];
            points[i] += moonBody.transform.position;
            theta     += dtheta;
        }
        // close the path (credit for fix to R. Vincent)
        points[numPoints - 1]     = points[0];
        soiRenderer.positionCount = numPoints;
        soiRenderer.SetPositions(points);
    }
コード例 #23
0
    /// <summary>
    /// Take the Nbody objects in the nbodies list set them inactive and make them children of a new
    /// NBody object moving as the CM of the nbodies. This allows RigidBody mechanics during close
    /// encounters.
    /// </summary>
    private void Activate()
    {
        if (nbodies.Length < 2)
        {
            Debug.LogError("Need two or more nbodies");
            return;
        }

        GravityEngine ge = GravityEngine.Instance();

        // Step 1: calculate CM position and velocity
        Vector3d cmPos = new Vector3d(0, 0, 0);
        Vector3d cmVel = new Vector3d(0, 0, 0);

        float mass = 0f;

        rigidBodies = new Rigidbody[nbodies.Length];

        // RigidBody is assumed to be attached to one of the children (to keep model scale independent)
        int i = 0;

        foreach (NBody nbody in nbodies)
        {
            rigidBodies[i] = nbody.GetComponentInChildren <Rigidbody>();
            //rigidBodies[i] = nbody.GetComponent<Rigidbody>();
            if (rigidBodies[i] == null)
            {
                Debug.LogError("Abort - No rigidbody detected on " + nbody.gameObject.name);
                return;
            }
            mass  += rigidBodies[i].mass;
            cmPos += rigidBodies[i].mass * ge.GetPositionDoubleV3(nbody);
            cmVel += rigidBodies[i].mass * ge.GetVelocityDoubleV3(nbody);
            i++;
        }
        cmPos /= mass;
        cmVel /= mass;
        Debug.LogFormat("CM p={0} v={1} mass={2}", cmPos.ToVector3(), cmVel.ToVector3(), mass);

        // Step2: Inactivate the NBodies and make children of a new NBody object
        priorParents = new Transform[nbodies.Length];
        cmObject     = new GameObject("DockingGroupCM");
        cmNbody      = cmObject.AddComponent <NBody>();

        // Set cm pos/vel
        // NBody InitPosition will use transform or initialPos base on units. Set both.
        cmNbody.initialPos         = cmPos.ToVector3() * ge.physToWorldFactor;
        cmNbody.transform.position = cmNbody.initialPos;
        ge.AddBody(cmObject);
        ge.SetVelocity(cmNbody, cmVel.ToVector3());
        Debug.LogFormat("set pos={0} actual={1}", cmPos.ToVector3(), ge.GetPhysicsPosition(cmNbody));
        i = 0;
        foreach (NBody nbody in nbodies)
        {
            Vector3d pos = ge.GetPositionDoubleV3(nbody);
            Vector3d vel = ge.GetVelocityDoubleV3(nbody);
            priorParents[i] = nbody.gameObject.transform.parent;
            ge.InactivateBody(nbody.gameObject);
            nbody.gameObject.transform.parent = cmObject.transform;
            // position wrt to CM. Need to convert to Unity scene units from GE Internal
            pos = (pos - cmPos) * ge.physToWorldFactor;
            vel = GravityScaler.ScaleVelPhysToScene(vel - cmVel);
            nbody.transform.localPosition = pos.ToVector3();
            rigidBodies[i].velocity       = vel.ToVector3();
            // rigidBodies[i].isKinematic = false;
            i++;
            Debug.LogFormat("body {0} p={1} v={2}", nbody.gameObject.name, pos.ToVector3(), vel.ToVector3());
        }
        // activate any RCS elements
        foreach (ReactionControlSystem r in rcs)
        {
            if (r != null)
            {
                r.SetRigidBodyEnabled(true);
            }
        }
    }
コード例 #24
0
 void Start()
 {
     worldState  = GravityEngine.Instance().GetWorldState();
     accelGEtoSI = GravityScaler.AccelerationScaleInternalToGEUnits() / GravityScaler.AccelSItoGEUnits();
 }
コード例 #25
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;

        NBody   nbody       = (NBody)target;
        float   mass        = 0f;
        float   size        = 0.1f;
        bool    autoSize    = true;
        Vector3 velocity    = Vector3.zero;
        Vector3 initialPos  = Vector3.zero;
        bool    rotateFrame = false;

        if (GravityEngine.Instance() == null)
        {
            EditorGUILayout.LabelField("Require a GravityEngine in the scene to", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("display NBody component.", EditorStyles.boldLabel);
        }

        GravityScaler.Units units = GravityEngine.Instance().units;
        string mass_prompt        = string.Format("Mass ({0})", GravityScaler.MassUnits(units));

        mass = EditorGUILayout.DelayedFloatField(new GUIContent(mass_prompt, mTip), (float)nbody.mass);

        // If the velocity is controlled by an EllipseBase, or this NBody is the direct child of
        // BinaryPair or ThreeeBodySolution then don't allowit to be controlled.
        string controlledBy = null;

        if (nbody.transform.gameObject.GetComponent <OrbitEllipse>() != null)
        {
            controlledBy = "Initial position/Velocity is set by ellipse parameters.";
        }
        else if (nbody.transform.gameObject.GetComponent <OrbitHyper>() != null)
        {
            controlledBy = "Initial position/Velocity is set by hyperbola parameters.";
        }
        else if (nbody.transform.parent != null)
        {
            if (nbody.transform.parent.gameObject.GetComponent <BinaryPair>() != null)
            {
                controlledBy = "Initial position/Velocity is set by BinaryPair parent.";
            }
            else if (nbody.transform.parent.gameObject.GetComponent <ThreeBodySolution>() != null)
            {
                controlledBy = "Initial position/Velocity is set by ThreeBodySolution parent.";
            }
        }
        if (controlledBy == null)
        {
            switch (units)
            {
            case GravityScaler.Units.DIMENSIONLESS:
                EditorGUILayout.LabelField("Initial position set via transform");
                velocity   = EditorGUILayout.Vector3Field(new GUIContent("Velocity", velTip), nbody.vel);
                initialPos = nbody.transform.position;
                break;

            default:
                string prompt = string.Format("Initial Pos ({0})", GravityScaler.LengthUnits(units));
                initialPos = EditorGUILayout.Vector3Field(new GUIContent(prompt, iposTip), nbody.initialPos);

                prompt   = string.Format("Velocity ({0})", GravityScaler.VelocityUnits(units));
                velocity = EditorGUILayout.Vector3Field(new GUIContent(prompt, velTip), nbody.vel);
                break;
            }
        }
        else
        {
            EditorGUILayout.LabelField(controlledBy, EditorStyles.boldLabel);
            //EditorGUILayout.LabelField(string.Format("vel= {0:F2} {1:F2} {2:F2}", nbody.vel.x, nbody.vel.y, nbody.vel.z));
        }


        // particle capture size
        EditorGUIUtility.labelWidth = 200f;
        EditorGUIUtility.fieldWidth = 20f;
        rotateFrame = EditorGUILayout.Toggle(new GUIContent("Rotate frame in orbit", rotateTip), nbody.rotateFrame);
        autoSize    = EditorGUILayout.Toggle(new GUIContent("Automatic particle capture size", autoTip), nbody.automaticParticleCapture);
        EditorGUIUtility.labelWidth = 0;
        EditorGUIUtility.fieldWidth = 0;
        if (!autoSize)
        {
            EditorGUIUtility.labelWidth = 200f;
            EditorGUIUtility.fieldWidth = 40f;
            size = EditorGUILayout.FloatField(new GUIContent("Particle capture radius", sizeTip), (float)nbody.size);
            EditorGUIUtility.labelWidth = 0;
            EditorGUIUtility.fieldWidth = 0;
        }
        else
        {
            float detectedSize = nbody.CalculateSize();
            if (detectedSize < 0)
            {
                EditorGUILayout.LabelField("Did not detect a child with a MeshFilter.", EditorStyles.boldLabel);
                EditorGUILayout.LabelField("Using size=" + size);
            }
            else
            {
                EditorGUILayout.LabelField("Particle Capture radius=" + detectedSize);
                size = detectedSize;
            }
        }
        if (mass < 0)
        {
            mass = 0;
        }

        if (nbody.transform.hasChanged)
        {
            // User has dragged the object and the transform has changed, need
            // to change the initial Pos to correspond to this position in the correct units
            if (units != GravityScaler.Units.DIMENSIONLESS)
            {
                initialPos = nbody.transform.position / GravityEngine.Instance().GetLengthScale();
            }
            nbody.initialPos           = initialPos;
            nbody.transform.hasChanged = false;
        }

        if (GUI.changed)
        {
            Undo.RecordObject(nbody, "NBody Change");
            nbody.mass        = FixNaN.FixIfNaN(mass);
            nbody.vel         = FixNaN.FixIfNaN(velocity);
            nbody.size        = size;
            nbody.rotateFrame = rotateFrame;
            nbody.automaticParticleCapture = autoSize;
            nbody.initialPos = initialPos;
            Debug.Log("new v=" + velocity);
            // must be after initialPos is updated
            nbody.ApplyScale(GravityEngine.Instance().GetLengthScale(),
                             GravityEngine.Instance().GetVelocityScale());
            EditorUtility.SetDirty(nbody);
        }
    }
コード例 #26
0
 /// <summary>
 /// Set the maneuver time in world units (e.g. in ORBITAL units in
 /// hours).
 /// </summary>
 /// <param name="time"></param>
 public void SetTimeScaled(float time)
 {
     worldTime = time / GravityScaler.GetGameSecondPerPhysicsSecond();
 }
コード例 #27
0
 /// <summary>
 /// Return the dV in scaled units.
 /// </summary>
 /// <returns></returns>
 public float GetDvScaled()
 {
     return(dV / GravityScaler.GetVelocityScale());
 }
コード例 #28
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;
        EllipseBase ellipseBase = (EllipseBase)target;
        // fields in class
        GameObject centerObject = null;

        EllipseBase.ParamBy paramBy = EllipseBase.ParamBy.AXIS_A;
        float ecc         = 0;
        float a           = 0;
        float p           = 0;
        float omega_uc    = 0;
        float omega_lc    = 0;
        float inclination = 0;
        float phase       = 0;

        if (!(target is BinaryPair))
        {
            centerObject = (GameObject)EditorGUILayout.ObjectField(
                new GUIContent("CenterObject", centerTip),
                ellipseBase.centerObject,
                typeof(GameObject),
                true);
        }

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Ellipse Parameters", EditorStyles.boldLabel);

        // If there is a SolarBody, it is the one place data can be changed. The EB holds the
        // orbit scaled per SolarSystem scale.
        SolarBody sbody = ellipseBase.GetComponent <SolarBody>();

        if (sbody != null)
        {
            EditorGUILayout.LabelField("\tEllipse parameters controlled by SolarBody settings.");
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Semi-Major Axis", "a", ellipseBase.a), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Eccentricity", "e", ellipseBase.ecc), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Incliniation", "i", ellipseBase.inclination), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Arg. of pericenter", "\u03c9", ellipseBase.omega_lc), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Longitude of node", "\u03a9", ellipseBase.omega_uc), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25}\t ({1,1})\t  {2}",
                                                     "Phase", "M", ellipseBase.phase), EditorStyles.wordWrappedLabel);
            return;
        }

        paramBy =
            (EllipseBase.ParamBy)EditorGUILayout.EnumPopup(new GUIContent("Parameter Choice", paramTip), ellipseBase.paramBy);

        ecc = EditorGUILayout.Slider(new GUIContent("Eccentricity", eTip), ellipseBase.ecc, 0f, 0.99f);


        axisUpdated = false;
        // backwards compatibility when loading scenes before unit scaling:
        if (ellipseBase.a_scaled < 0)
        {
            axisUpdated = true;
        }
        GravityScaler.Units units = GravityEngine.Instance().units;
        if (ellipseBase.paramBy == EllipseBase.ParamBy.AXIS_A)
        {
            float oldLabelWidth = EditorGUIUtility.labelWidth;
            EditorGUIUtility.labelWidth = oldLabelWidth + 30f;
            string prompt = string.Format("Semi-Major Axis (a) [{0}]", GravityScaler.LengthUnits(units));
            a = EditorGUILayout.DelayedFloatField(new GUIContent(prompt, aTip), ellipseBase.a);
            if (a != ellipseBase.a)
            {
                axisUpdated = true;
            }
            EditorGUILayout.LabelField("Scaled a (Unity units):   " + ellipseBase.a_scaled);
            EditorGUIUtility.labelWidth = oldLabelWidth;
            p = a * (1 - ecc);
        }
        else
        {
            string prompt = string.Format("Pericenter [{0}]", GravityScaler.LengthUnits(units));
            p = EditorGUILayout.DelayedFloatField(new GUIContent(prompt, pTip), ellipseBase.p);
            if (p != ellipseBase.p)
            {
                axisUpdated = true;
            }
            EditorGUILayout.LabelField("Scaled p (Unity units) " + ellipseBase.p_scaled);
            a = p / (1 - ecc);
        }
        // implementation uses AngleAxis, so degrees are more natural
        omega_uc    = EditorGUILayout.Slider(new GUIContent("\u03a9 (Longitude of AN)", omega_ucTip), ellipseBase.omega_uc, 0, 360f);
        omega_lc    = EditorGUILayout.Slider(new GUIContent("\u03c9 (AN to Pericenter)", omega_lcTip), ellipseBase.omega_lc, 0, 360f);
        inclination = EditorGUILayout.Slider(new GUIContent("Inclination", inclinationTip), ellipseBase.inclination, 0f, 180f);
        // physics uses radians - but ask user for degrees to be consistent
        phase = EditorGUILayout.Slider(new GUIContent("Starting Phase", phaseTip), ellipseBase.phase, 0, 360f);

        // Checking the Event type lets us update after Undo and Redo commands.
        // A redo updates _lengthScale but does not run the setter
//        if (Event.current.type == EventType.ExecuteCommand &&
//            Event.current.commandName == "UndoRedoPerformed") {
//			ellipseBase.ApplyScale(GravityEngine.Instance().GetLengthScale());
//        }

        if (GUI.changed)
        {
            Undo.RecordObject(ellipseBase, "EllipseBase Change");
            ellipseBase.a            = a;
            ellipseBase.p            = p;
            ellipseBase.ecc          = ecc;
            ellipseBase.centerObject = centerObject;
            ellipseBase.omega_lc     = omega_lc;
            ellipseBase.omega_uc     = omega_uc;
            ellipseBase.inclination  = inclination;
            ellipseBase.phase        = phase;
            ellipseBase.paramBy      = paramBy;
            EditorUtility.SetDirty(ellipseBase);
        }
    }
コード例 #29
0
 /// <summary>
 /// Set the deltaV for a scalar maneuver in world units (e.g. in ORBITAL
 /// units set velocity in km/hr)
 /// </summary>
 /// <param name="newDv"></param>
 public void SetDvScaled(float newDv)
 {
     dV = newDv * GravityScaler.GetVelocityScale();
 }
コード例 #30
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;
        OrbitUniversal orbitU         = (OrbitUniversal)target;
        bool           displayAndExit = false;

        // check there is an NBody, if not likely a synthesized Orbit as part of a predictor
        if (orbitU.GetComponent <NBody>() == null)
        {
            EditorGUILayout.LabelField("Ellipse parameters determined from position/velocity.");
            EditorGUILayout.LabelField("(Orbit Predictor).");
            displayAndExit = true;
        }

        // If there is a SolarBody, it is the one place data can be changed. The EB holds the
        // orbit scaled per SolarSystem scale.
        SolarBody sbody = orbitU.GetComponent <SolarBody>();

        if (sbody != null)
        {
            EditorGUILayout.LabelField("Ellipse parameters controlled by SolarBody settings.");
            displayAndExit = true;
        }
        if (displayAndExit)
        {
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Semi-Major Axis", "a", orbitU.GetMajorAxisInspector()), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Eccentricity", "e", orbitU.eccentricity), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Incliniation", "i", orbitU.inclination), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Arg. of pericenter", "\u03c9", orbitU.omega_lc), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Longitude of node", "\u03a9", orbitU.omega_uc), EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField(string.Format("   {0,-25} ({1,1})\t  {2}",
                                                     "Phase", "M", orbitU.phase), EditorStyles.wordWrappedLabel);
            return;
        }

        // fields in class
        NBody centerNBody = null;

        OrbitUniversal.InputMode inputMode = orbitU.inputMode;
        double ecc         = orbitU.eccentricity;
        double p_inspector = orbitU.p_inspector;
        double omega_uc    = 0;
        double omega_lc    = 0;
        double inclination = 0;
        double phase       = 0;

        bool sizeUpdate = false;

        WarnAboutKeplerSeq(orbitU);

        centerNBody = (NBody)EditorGUILayout.ObjectField(
            new GUIContent("Center NBody", centerTip),
            orbitU.centerNbody,
            typeof(NBody),
            true);


        OrbitUniversal.EvolveMode evolveMode = orbitU.evolveMode;
        evolveMode = (OrbitUniversal.EvolveMode)EditorGUILayout.EnumPopup(new GUIContent("Evolve Mode", modeTip), evolveMode);

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Shape Parameters", EditorStyles.boldLabel);


        inputMode = (OrbitUniversal.InputMode)
                    EditorGUILayout.EnumPopup(new GUIContent("Parameter Choice", paramTip), orbitU.inputMode);

        sizeUpdate = false;
        GravityScaler.Units units = GravityEngine.Instance().units;
        string promptp            = string.Format("Semi-parameter (p) [{0}]", GravityScaler.LengthUnits(units));

        // The values for orbit size and shape can be entered in several ways. OrbitUniversal supports
        // these values as doubles (which is probably overkill in most case). Provide an explicit double mode
        // but also allow sliders (which reduce the value to a float).

        // The editor script changes p_inspector. (p in OU is scaled for GE internal units)
        switch (inputMode)
        {
        case OrbitUniversal.InputMode.ELLIPSE_MAJOR_AXIS_A:
            EditorGUILayout.LabelField("Ellipse with float/sliders using semi-major axis.");
            ecc = EditorGUILayout.Slider(new GUIContent("Eccentricity", eTip), (float)orbitU.eccentricity, 0f, 0.99f);
            GetMajorAxis(orbitU, ref p_inspector, ref sizeUpdate, units);
            break;

        case OrbitUniversal.InputMode.ELLIPSE_APOGEE_PERIGEE:
            EditorGUILayout.LabelField("Ellipse with float/sliders using agogee/perigee.");
            EditorGUILayout.LabelField("MUST use <Return> after updating values!");
            double apogee_old  = orbitU.GetApogeeInspector();
            double apogee      = EditorGUILayout.DelayedDoubleField(new GUIContent("Apogee", eTip), apogee_old);
            double perigee_old = orbitU.GetPerigeeInspector();
            double perigee     = EditorGUILayout.DelayedDoubleField(new GUIContent("Perigee", eTip), perigee_old);
            // enforce apogee > perigee
            if (apogee < perigee)
            {
                apogee = perigee;
            }

            if (!EditorApplication.isPlaying && (apogee != apogee_old) || (perigee != perigee_old))
            {
                orbitU.SetSizeWithApogeePerigee(apogee, perigee);
                sizeUpdate = true;
                // Need to update ecc and p with new values
                p_inspector = orbitU.p_inspector;
                ecc         = orbitU.eccentricity;
            }
            EditorGUILayout.LabelField(string.Format("Require Apogee > Perigee", ecc, p_inspector));
            EditorGUILayout.LabelField(string.Format("Apogee/Perigee result in: eccentricty={0:0.00}, p={1:0.00}", ecc, p_inspector));
            break;

        case OrbitUniversal.InputMode.ECC_PERIGEE:
            EditorGUILayout.LabelField("Orbit with double using eccentricity/perigee.");
            EditorGUILayout.LabelField("MUST use <Return> after updating values!");
            double old_ecc = orbitU.eccentricity;
            ecc = EditorGUILayout.DelayedDoubleField(new GUIContent("Eccentricity", eTip), orbitU.eccentricity);
            double hperigee_old = orbitU.GetPerigeeInspector();
            double hperigee     = EditorGUILayout.DelayedDoubleField(new GUIContent("Perigee", eTip), hperigee_old);
            if (!EditorApplication.isPlaying && ((hperigee != hperigee_old) || (old_ecc != ecc)))
            {
                orbitU.SetSizeWithEccPerigee(ecc, hperigee);
                sizeUpdate = true;
                // Need to update ecc and p with new values
                p_inspector = orbitU.p_inspector;
                ecc         = orbitU.eccentricity;
            }
            EditorGUILayout.LabelField(string.Format("Apogee/Perigee result in: eccentricty={0:0.00}, p={1:0.00}", ecc, p_inspector));
            break;


        case OrbitUniversal.InputMode.DOUBLE:
            EditorGUILayout.LabelField("Specify values with double precision using semi-parameter");
            EditorGUILayout.LabelField("MUST use <Return> after updating values!");
            // no sliders (they do float)
            ecc = EditorGUILayout.DelayedDoubleField(new GUIContent("Eccentricity", eTip), orbitU.eccentricity);
            double old_p = orbitU.p_inspector;
            p_inspector = EditorGUILayout.DelayedDoubleField(new GUIContent(promptp, pTip), orbitU.p_inspector);
            if (old_p != p_inspector)
            {
                sizeUpdate = true;
            }
            break;

        case OrbitUniversal.InputMode.DOUBLE_ELLIPSE:
            EditorGUILayout.LabelField("Specify values with double precision using semi-parameter");
            EditorGUILayout.LabelField("MUST use <Return> after updating values!");
            // no sliders (they do float)
            ecc = EditorGUILayout.DelayedDoubleField(new GUIContent("Eccentricity", eTip), orbitU.eccentricity);
            GetMajorAxis(orbitU, ref p_inspector, ref sizeUpdate, units);
            break;

        default:
            Debug.LogWarning("Unknown input mode - internal error");
            break;
        }
        if (!EditorApplication.isPlaying && (p_inspector != orbitU.p))
        {
            sizeUpdate = true;
        }
        EditorGUILayout.LabelField("Scaled p (Unity units):   " + orbitU.p);

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Orientation Parameters", EditorStyles.boldLabel);
        if ((inputMode != OrbitUniversal.InputMode.DOUBLE) && (inputMode != OrbitUniversal.InputMode.DOUBLE_ELLIPSE))
        {
            // implementation uses AngleAxis, so degrees are more natural
            omega_uc    = EditorGUILayout.Slider(new GUIContent("\u03a9 (Longitude of AN)", omega_ucTip), (float)orbitU.omega_uc, 0, 360f);
            omega_lc    = EditorGUILayout.Slider(new GUIContent("\u03c9 (AN to Pericenter)", omega_lcTip), (float)orbitU.omega_lc, 0, 360f);
            inclination = EditorGUILayout.Slider(new GUIContent("Inclination", inclinationTip), (float)orbitU.inclination, 0f, 180f);
            // physics uses radians - but ask user for degrees to be consistent
            phase = EditorGUILayout.Slider(new GUIContent("Starting Phase", phaseTip), (float)orbitU.phase, 0, 360f);
        }
        else
        {
            // DOUBLE, so no sliders
            omega_uc    = EditorGUILayout.DoubleField(new GUIContent("\u03a9 (Longitude of AN)", omega_ucTip), orbitU.omega_uc);
            omega_lc    = EditorGUILayout.DoubleField(new GUIContent("\u03c9 (AN to Pericenter)", omega_lcTip), orbitU.omega_lc);
            inclination = EditorGUILayout.DoubleField(new GUIContent("Inclination", inclinationTip), orbitU.inclination);
            phase       = EditorGUILayout.DoubleField(new GUIContent("Starting Phase", phaseTip), orbitU.phase);
        }

        if (GUI.changed)
        {
            Undo.RecordObject(orbitU, "EllipseBase Change");
            orbitU.p_inspector  = p_inspector;
            orbitU.eccentricity = ecc;
            orbitU.centerNbody  = centerNBody;
            orbitU.omega_lc     = omega_lc;
            orbitU.omega_uc     = omega_uc;
            orbitU.inclination  = inclination;
            orbitU.phase        = phase;
            orbitU.inputMode    = inputMode;
            orbitU.evolveMode   = evolveMode;
            EditorUtility.SetDirty(orbitU);
        }

        if (sizeUpdate)
        {
            orbitU.ApplyScale(GravityEngine.Instance().GetLengthScale());
        }
    }