예제 #1
0
    /// <summary>
    /// Set the integrator required for the chosen algorithm
    /// </summary>
    /// <param name="algorithm"></param>
    public void SetAlgorithmAndForce(GravityEngine.Algorithm algorithm, IForceDelegate forceDelegate)
    {
        this.forceDelegate = forceDelegate;
        // cast may be null if no force selection
        if (forceDelegate is SelectiveForceBase)
        {
            selectiveForce = (SelectiveForceBase)forceDelegate;
        }
        switch (algorithm)
        {
        case GravityEngine.Algorithm.LEAPFROG:
            integrator = new LeapFrogIntegrator(forceDelegate);
            break;

        //case GravityEngine.Algorithm.LEAPFROG_JOB:
        //    integrator = new LeapFrogJob(forceDelegate);
        //    break;
        case GravityEngine.Algorithm.HERMITE8:
            integrator = new HermiteIntegrator(forceDelegate);
            break;

        case GravityEngine.Algorithm.AZTRIPLE:
            integrator = new AZTripleIntegrator();
            break;

        default:
            Debug.LogError("Unknown algortithm");
            break;
        }
    }
예제 #2
0
    public HermiteIntegrator(IForceDelegate force)
    {
                #pragma warning disable 162             // disable unreachable code warning
        if (GravityEngine.DEBUG)
        {
            Debug.Log("Instantiated with " + force);
        }
                #pragma warning restore 162

        forceDelegate = force;
    }
예제 #3
0
    /// <summary>
    /// Initializes a new instance of the <see cref="LeapFrogIntegrator"/> class.
    /// An optional force delegate can be provided if non-Newtonian gravity is
    /// desired.
    /// </summary>
    /// <param name="force">Force.</param>
    public LeapFrogIntegrator(IForceDelegate force)
    {
                #pragma warning disable 162             // disable unreachable code warning
        if (GravityEngine.DEBUG)
        {
            Debug.Log("Leapfrog instantiated with force= " + force);
        }
                #pragma warning restore 162

        forceDelegate = force;
    }
예제 #4
0
 // Update is called once per frame
 void Update()
 {
     if (!setup)
     {
         setup = true;
         IForceDelegate force = GravityEngine.Instance().GetForceDelegate();
         if (force != null)
         {
             SelectiveForceBase selectiveForce = (SelectiveForceBase)force;
             if (selectiveForce != null)
             {
                 selectiveForce.ForceSelection(a, b, false);
             }
         }
     }
 }
예제 #5
0
    public static IForceDelegate InstantiateForce(Forces force, GameObject host)
    {
        IForceDelegate forceD = null;

        switch (force)
        {
        case Forces.Gravity:
            // leave as null - GE has gravity built-in
            break;

        case Forces.InverseR:
            forceD = new InverseR();
            break;

        case Forces.InverseR3:
            forceD = new InverseR3();
            break;

        case Forces.ForceR:
            forceD = new ForceR();
            break;

        case Forces.ForceR2:
            forceD = new ForceR2();
            break;

        case Forces.Custom:
            forceD = host.GetComponent <IForceDelegate>();
            if (forceD == null)
            {
                Debug.LogError("Custom IForceDelegate is not attached to " + host.name);
            }
            break;

        default:
            Debug.LogError("Unknown force (was it added to ForceChooser? => " + force);
            break;
        }

        return(forceD);
    }
예제 #6
0
    public override void OnInspectorGUI()
    {
        GUI.changed = false;
        GravityEngine gravityEngine = (GravityEngine)target;
        float         massScale     = gravityEngine.massScale;
        float         timeScale     = gravityEngine.timeScale;
        float         lengthScale   = gravityEngine.lengthScale;

        float physToWorldFactor = gravityEngine.physToWorldFactor;

        bool optimizeMassless = gravityEngine.optimizeMassless;
        bool detectNbodies    = gravityEngine.detectNbodies;
        bool evolveAtStart    = gravityEngine.evolveAtStart;
        bool scaling          = gravityEngine.editorShowScale;
        bool showAdvanced     = gravityEngine.editorShowAdvanced;
        bool showTrajectory   = gravityEngine.editorShowTrajectory;
        bool cmFoldout        = gravityEngine.editorCMfoldout;
        bool mapToScene       = gravityEngine.mapToScene;

        bool       trajectoryPrediction = gravityEngine.trajectoryPrediction;
        float      trajectoryTime       = gravityEngine.trajectoryTime;
        GameObject trajCanvas           = gravityEngine.trajectoryCanvas;
        GameObject markerParent         = gravityEngine.markerParent;
        float      computeFactor        = gravityEngine.trajectoryComputeFactor;

        int stepsPerFrame         = gravityEngine.stepsPerFrame;
        int particleStepsPerFrame = gravityEngine.particleStepsPerFrame;

        GravityEngine.Algorithm algorithm = GravityEngine.Algorithm.LEAPFROG;
        ForceChooser.Forces     force     = ForceChooser.Forces.Gravity;
        GravityScaler.Units     units     = GravityScaler.Units.DIMENSIONLESS;

        EditorGUIUtility.labelWidth = 200;

        mapToScene = EditorGUILayout.Toggle(new GUIContent("Use Transform to Reposition", mapTip), mapToScene);

        EditorGUIUtility.labelWidth = 150;

        // SCALING
        scaling = EditorGUILayout.Foldout(scaling, "Scaling");
        if (scaling)
        {
            units =
                (GravityScaler.Units)EditorGUILayout.EnumPopup(new GUIContent("Units", unitsTip), gravityEngine.units);
            EditorGUILayout.LabelField("Scaling values change when <ENTER> ispressed.");

            switch (units)
            {
            case GravityScaler.Units.DIMENSIONLESS:
                // only have mass scale in DL case
                EditorGUILayout.LabelField("Use mass scale to control scene speed.");
                EditorGUILayout.LabelField("(More massive = faster)");
                massScale = EditorGUILayout.DelayedFloatField(new GUIContent("Mass Scale", mTip), gravityEngine.massScale);
                break;

            case GravityScaler.Units.SI:
                // no mass scale is controlled by time exclusivly
                EditorGUILayout.LabelField("m/kg/sec.");
                // meters per Unity unit in the case of meters
                lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per m", timeTip), gravityEngine.lengthScale);
                timeScale   = EditorGUILayout.DelayedFloatField(new GUIContent("Game sec. per sec.", timeTip), gravityEngine.timeScale);
                break;

            case GravityScaler.Units.ORBITAL:
                EditorGUILayout.LabelField("km/1E24 kg/hr");
                // Express in km per Unity unit km/U
                lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per km", timeTip), gravityEngine.lengthScale);
                timeScale   = EditorGUILayout.DelayedFloatField(new GUIContent("Game sec. per hour", timeTip), gravityEngine.timeScale);
                break;

            case GravityScaler.Units.SOLAR:
                EditorGUILayout.LabelField("AU/1E24 kg/year");
                lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per AU", timeTip), gravityEngine.lengthScale);
                timeScale   = EditorGUILayout.DelayedFloatField(new GUIContent("Game Sec per year", timeTip), gravityEngine.timeScale);
                break;
            }
        }

        // TRAJECTORY PREDICTION
        showTrajectory = EditorGUILayout.Foldout(showTrajectory, "Trajectory Prediction");
        if (showTrajectory)
        {
            trajectoryPrediction = EditorGUILayout.Toggle(new GUIContent("Trajectory Prediction", trajTip), trajectoryPrediction);
            trajectoryTime       = EditorGUILayout.FloatField(new GUIContent("Trajectory Time", trajTimeTip), trajectoryTime);
            computeFactor        = EditorGUILayout.FloatField(new GUIContent("Re-computes per frame)", trajResetTip), computeFactor);
            trajCanvas           = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Canvas for Text (optional)", trajCanvasTip),
                                                                           trajCanvas, typeof(GameObject), true);
            markerParent = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Time Marker Parent (optional)", markerTip),
                                                                   markerParent, typeof(GameObject), true);
        }

        // ADVANCED
        showAdvanced = EditorGUILayout.Foldout(showAdvanced, "Advanced");
        if (showAdvanced)
        {
            algorithm =
                (GravityEngine.Algorithm)EditorGUILayout.EnumPopup(new GUIContent("Algorithm", algoTip), gravityEngine.algorithm);

            // Force selection is tangled with choice of integrator and scale - so needs to be here
            force =
                (ForceChooser.Forces)EditorGUILayout.EnumPopup(new GUIContent("Force", forceTip), gravityEngine.force);
            if (force == ForceChooser.Forces.Custom)
            {
                IForceDelegate force_delegate = gravityEngine.GetComponent <IForceDelegate>();
                if (force_delegate == null)
                {
                    EditorGUILayout.LabelField("  Attach a Force Delegate to this object.", EditorStyles.boldLabel);
                }
                else
                {
                    EditorGUILayout.LabelField("  Force delegate: " + force_delegate.GetType());
                }
            }
            if (force != ForceChooser.Forces.Gravity)
            {
                EditorGUILayout.LabelField("    Note: Orbit predictors assume Newtonian gravity");
                EditorGUILayout.LabelField("    They are not accurate for other forces.");
            }

            optimizeMassless = EditorGUILayout.Toggle(new GUIContent("Optimize Massless Bodies", mlessTip),
                                                      gravityEngine.optimizeMassless);
            detectNbodies     = EditorGUILayout.Toggle(new GUIContent("Automatically Add NBody objects", autoAddTip), gravityEngine.detectNbodies);
            evolveAtStart     = EditorGUILayout.Toggle(new GUIContent("Evolve at Start", autoStartTip), gravityEngine.evolveAtStart);
            physToWorldFactor = EditorGUILayout.FloatField(new GUIContent("Physics to World Scale", phyWTip), gravityEngine.physToWorldFactor);

            EditorGUILayout.LabelField("Steps per frame:");
            stepsPerFrame         = EditorGUILayout.IntField(new GUIContent("  Massive Bodies", stepTip), stepsPerFrame);
            particleStepsPerFrame = EditorGUILayout.IntField(new GUIContent("  Particles", pstepTip), particleStepsPerFrame);
        }
        // Switch bodies list on/off based on option
        if (!gravityEngine.detectNbodies)
        {
            // use native Inspector look & feel for bodies object
            EditorGUILayout.LabelField("Control Nbody in following gameObjects (and children)", EditorStyles.boldLabel);
            SerializedProperty bodiesProp = serializedObject.FindProperty("bodies");
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(bodiesProp, true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
        }
        else
        {
            EditorGUILayout.LabelField("NBody objects will be detected automatically", EditorStyles.boldLabel);
        }
        // Show the CM and the velocity of the CM
        cmFoldout = EditorGUILayout.Foldout(cmFoldout, "Center of Mass Info");
        if (cmFoldout)
        {
            EditorGUILayout.LabelField("Center of Mass:" + gravityEngine.GetWorldCenterOfMass());
            EditorGUILayout.LabelField("CM Velocity:" + gravityEngine.GetWorldCenterOfMassVelocity());
        }


        // 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")
        {
            // explicitly re-set so setter code will run.
            gravityEngine.lengthScale = lengthScale;
        }

        if (GUI.changed)
        {
            Undo.RecordObject(gravityEngine, "GE Change");
            gravityEngine.mapToScene = mapToScene;

            gravityEngine.timeScale = timeScale;
            gravityEngine.massScale = massScale;
            // This runs a setter in GE that will do a rescale of the scene if necessary
            gravityEngine.lengthScale       = lengthScale;
            gravityEngine.units             = units;
            gravityEngine.physToWorldFactor = physToWorldFactor;
            gravityEngine.optimizeMassless  = optimizeMassless;
            gravityEngine.detectNbodies     = detectNbodies;

            gravityEngine.editorShowTrajectory    = showTrajectory;
            gravityEngine.trajectoryPrediction    = trajectoryPrediction;
            gravityEngine.trajectoryTime          = trajectoryTime;
            gravityEngine.trajectoryCanvas        = trajCanvas;
            gravityEngine.markerParent            = markerParent;
            gravityEngine.trajectoryComputeFactor = computeFactor;

            gravityEngine.algorithm             = algorithm;
            gravityEngine.force                 = force;
            gravityEngine.evolveAtStart         = evolveAtStart;
            gravityEngine.editorShowScale       = scaling;
            gravityEngine.editorShowAdvanced    = showAdvanced;
            gravityEngine.editorCMfoldout       = cmFoldout;
            gravityEngine.stepsPerFrame         = stepsPerFrame;
            gravityEngine.particleStepsPerFrame = particleStepsPerFrame;
            EditorUtility.SetDirty(gravityEngine);
        }
    }
    /// <summary>
    /// Evolves particles using massice bodies the with force delegate provided.
    /// </summary>
    /// <returns>The with force.</returns>
    /// <param name="evolveTime">Evolve time.</param>
    /// <param name="numBodies">Number bodies.</param>
    /// <param name="m">M.</param>
    /// <param name="r_m">R m.</param>
    /// <param name="size2">Size2.</param>
    /// <param name="info">Info.</param>
    /// <param name="force">Force.</param>
    public double EvolveWithForce(double evolveTime,
                                  int numBodies,
                                  GravityState gravityState,
                                  ref double[] size2,
                                  ref byte[] info,
                                  IForceDelegate force)
    {
        // do nothing if all inactive
        if (inactive == null || allInactive)
        {
            return(evolveTime);                 // Particle system has not init-ed yet or is done
        }
        //  (did not work in Start() -> Unity bug? Init sequencing?)
        if (!playing)
        {
            gravityParticles.Play();
            playing = true;
        }
        double[] m = gravityState.m;
        double[,] r_m = gravityState.r;

        ParticleLifeCycleHandler(numBodies, gravityState, ref info);
        //
        // physics integration of particles in the field of the masses passed in by NBE
        //
        double time = 0;

        while (time < evolveTime)
        {
            time += dt;
            // Update v and r
            for (int i = 0; i < particleCount; i++)
            {
                if (!inactive[i])
                {
                    v[i, 0] += a[i, 0] * 0.5 * dt;
                    r[i, 0] += v[i, 0] * dt;
                    v[i, 1] += a[i, 1] * 0.5 * dt;
                    r[i, 1] += v[i, 1] * dt;
                    v[i, 2] += a[i, 2] * 0.5 * dt;
                    r[i, 2] += v[i, 2] * dt;
                }
            }
            // advance acceleration
            double[] rji = new double[GravityState.NDIM];
            double   r2;               // r squared
            double   r_sep;            // r
            double   accel;
            // a = 0
            for (int i = 0; i < particleCount; i++)
            {
                a[i, 0] = 0.0;
                a[i, 1] = 0.0;
                a[i, 2] = 0.0;
            }
            // calc a
            for (int i = 0; i < numBodies; i++)
            {
                // check mass has inactive clear
                if ((info[i] & GravityEngine.INACTIVE) == 0)
                {
                    for (int j = 0; j < particleCount; j++)
                    {
                        // only evolve active particles
                        if (!inactive[j])
                        {
                            rji[0] = r[j, 0] - r_m[i, 0];
                            rji[1] = r[j, 1] - r_m[i, 1];
                            rji[2] = r[j, 2] - r_m[i, 2];
                            // Particles that have moved outside of view are marked inactive

                            r2 = rji[0] * rji[0] + rji[1] * rji[1] + rji[2] * rji[2];
                            // Check for incursion on massive bodies and inactivate particles that have collided
                            // (Do not want to incur collider overhead per particle)
                            if (allowRemoval && r2 < size2[i])
                            {
                                inactive[j] = true;
                                inactiveCount++;
                                                                #pragma warning disable 162             // disable unreachable code warning
                                if (debugLogs)
                                {
                                    Debug.Log(string.Format("Inactivate particle {0} size2={1} due to object at {2} {3} {4} r2={5} count={6} p={7} {8}",
                                                            j, size2[i], r_m[i, 0], r_m[i, 1], r_m[i, 2], r2, inactiveCount, r[j, 0], r[j, 1]));
                                }
                                                                #pragma warning restore 162
                                if (oneTimeBurst)
                                {
                                    r[j, 0] = OUT_OF_VIEW;
                                }
                                else
                                {
                                    particles[j].remainingLifetime = 0;
                                }
                                continue;
                            }
                            r_sep    = System.Math.Sqrt(r2) + EPSILON;
                            accel    = force.CalcPseudoForce(r_sep, i, j);
                            a[j, 0] -= m[i] * accel * (rji[0] / r_sep);
                            a[j, 1] -= m[i] * accel * (rji[1] / r_sep);
                            a[j, 2] -= m[i] * accel * (rji[2] / r_sep);
                        }         // for j
                    }             // info
                }                 // for i
            }
            // update velocity
            for (int i = 0; i < particleCount; i++)
            {
                if (!inactive[i])
                {
                    v[i, 0] += a[i, 0] * 0.5 * dt;
                    v[i, 1] += a[i, 1] * 0.5 * dt;
                    v[i, 2] += a[i, 2] * 0.5 * dt;
                }
            }
        }         // while
        return(time);
    }
예제 #8
0
    /// <summary>
    /// Evolve the position of the active massless bodies based on the gravitational field by the
    /// objects provided in the arguments m, r_m and the specified force.
    ///
    /// This does not use the standard integrators since the list of bodies and the loop structure
    /// differs.
    /// </summary>
    /// <returns>The with force.</returns>
    /// <param name="evolveFor">Evolve for.</param>
    /// <param name="numMasses">Number masses.</param>
    /// <param name="m">M.</param>
    /// <param name="r_m">R m.</param>
    /// <param name="massive_info">Massive info.</param>
    /// <param name="force">Force.</param>
    public double EvolveWithForce(double evolveFor,
                                  int numMasses,
                                  ref double[] m,
                                  ref double[,] r_m,
                                  ref byte[] massive_info,
                                  IForceDelegate force)
    {
        if (numMasses == 0 && numBodies == 0)
        {
            return(evolveFor);
        }
        // advance acceleration
        double[] rji = new double[GravityEngine.NDIM];
        double   r2;          // r squared
        double   r_sep;       // r
        double   accel;
        double   time = 0.0;

        // Built in LeapFrog integrator
        while (time < evolveFor)
        {
            time += dt;
            // Update v using a from last cycle (1/2 step), then update r
            for (int i = 0; i < numBodies; i++)
            {
                if ((info[i] & GravityEngine.INACTIVE) == 0)
                {
                    for (int k = 0; k < GravityEngine.NDIM; k++)
                    {
                        v[i, k] += a[i, k] * dt / 2.0;
                        r[i, k] += v[i, k] * dt;
                    }
                }
            }
            // a = 0
            for (int i = 0; i < numBodies; i++)
            {
                a[i, 0] = 0.0;
                a[i, 1] = 0.0;
                a[i, 2] = 0.0;
            }
            // calc a
            for (int i = 0; i < numMasses; i++)
            {
                if ((massive_info[i] & GravityEngine.INACTIVE) == 0)
                {
                    for (int j = 0; j < numBodies; j++)
                    {
                        if ((info[j] & GravityEngine.INACTIVE) == 0)
                        {
                            rji[0] = r[j, 0] - r_m[i, 0];
                            rji[1] = r[j, 1] - r_m[i, 1];
                            rji[2] = r[j, 2] - r_m[i, 2];

                            r2    = 0;
                            r2   += rji[0] * rji[0];
                            r2   += rji[1] * rji[1];
                            r2   += rji[2] * rji[2];
                            r_sep = System.Math.Sqrt(r2) + EPSILON;
                            // Force equation
                            accel    = force.CalcF(r_sep);
                            a[j, 0] -= m[i] * accel * (rji[0] / r_sep);
                            a[j, 1] -= m[i] * accel * (rji[1] / r_sep);
                            a[j, 2] -= m[i] * accel * (rji[2] / r_sep);
                        }         // j
                    }             // if info
                }                 // i
            }
            // update velocity with other half step
            for (int i = 0; i < numBodies; i++)
            {
                if ((info[i] & GravityEngine.INACTIVE) == 0)
                {
                    v[i, 0] += a[i, 0] * dt / 2.0;
                    v[i, 1] += a[i, 1] * dt / 2.0;
                    v[i, 2] += a[i, 2] * dt / 2.0;
                }
            }
        }
        return(time);
    }
예제 #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LeapFrogIntegrator"/> class.
 /// An optional force delegate can be provided if non-Newtonian gravity is
 /// desired.
 /// </summary>
 /// <param name="force">Force.</param>
 public LeapFrogIntegrator(IForceDelegate force)
 {
     forceDelegate = force;
 }
예제 #10
0
    /// <summary>
    /// Clone constructor
    ///
    /// Creates a deep copy suitable for independent evolution as a trajectory or for maneuver iterations.
    /// Maneuvers will be executed but the callback to motify the owner of the maneuver will be skipped (only
    /// the real evolution will notify).
    /// </summary>
    /// <param name="fromState"></param>
    public GravityState(GravityState fromState)
    {
        m                       = new double[fromState.arraySize];
        r                       = new double[fromState.arraySize, NDIM];
        info                    = new byte[fromState.arraySize];
        size2                   = new double[fromState.arraySize];
        physicalTime            = new double[System.Enum.GetNames(typeof(Evolvers)).Length];
        arraySize               = fromState.arraySize;
        numBodies               = fromState.numBodies;
        fixedBodiesInIntegrator = fromState.fixedBodiesInIntegrator;
        onRails                 = fromState.onRails;


        // omitting hasTrajectories
        integrator = fromState.integrator.DeepClone();

        // don't copy particles, but need to init list
        gravityParticles = new List <GravityParticles>();

        // DO copy the maneuvers
        maneuverMgr = new ManeuverMgr(fromState.maneuverMgr);

        fixedBodies = new List <GravityEngine.FixedBody>(fromState.fixedBodies);

        for (int i = 0; i < physicalTime.Length; i++)
        {
            physicalTime[i] = fromState.physicalTime[i];
        }
        time           = fromState.time;
        forceDelegate  = fromState.forceDelegate;
        selectiveForce = fromState.selectiveForce;

        keplerDepthChanged = new List <GravityEngine.FixedBody>(fromState.keplerDepthChanged);

        if (fromState.masslessEngine != null)
        {
            masslessEngine = fromState.masslessEngine.DeepClone();
            masslessEngine.ResetTrajectories((float)fromState.time);
        }

        for (int i = 0; i < arraySize; i++)
        {
            m[i]     = fromState.m[i];
            info[i]  = fromState.info[i];
            size2[i] = fromState.size2[i];
            r[i, 0]  = fromState.r[i, 0];
            r[i, 1]  = fromState.r[i, 1];
            r[i, 2]  = fromState.r[i, 2];
        }

        // copies do not notify maneuver owners of maneuver completion. They are assumed to be "what if"
        // evolutions
        isCopy = true;

#pragma warning disable 162     // disable unreachable code warning
        if (GravityEngine.DEBUG)
        {
            Debug.Log("Created new (copy) gravityState");
        }
#pragma warning restore 162
    }