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