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;
    }
Example #2
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);
        }
    }
    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);
        }
    }
    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());
        }
    }