Thursday, November 17, 2022
HomeGame Developmentc++ - Why is my Moon not orbiting Earth in my physics...

c++ – Why is my Moon not orbiting Earth in my physics demo


I’m within the midst of creating a gravitational physique demo for my physics engine. For the demo, I’m making an attempt to simulate each all of the interior planets’ (Mercury-Venus-Earth-Mars) orbits across the solar, in addition to the orbit of the moon across the Earth. The planets are all working as anticipated, nevertheless the Moon doesn’t appear to need to orbit the Earth. I’m at an entire loss for why that is. I am fairly certain it is not that the gravity is calculated incorrectly, in any other case the planets wouldn’t all accurately orbit the solar. The calculations to find out the drive appearing on the moon start slightly below the whereas(!WindowShouldClose()) loop. Under is a (moderately prolonged) MCVE to see what I imply. I am hoping that it’s a conceptual difficulty about how I’ve arrange my preliminary situations greater than a coding mistake. Please word that it requires an set up of raylib

At present, the moon begins with the proper preliminary velocity relative to the solar (the mix of the Earth’s velocity relative to the Solar and the moon’s velocity relative to the Earth), nevertheless that velocity by no means considerably modifications, so the moon finally ends up getting into mainly a straight line endlessly. The “mainly” is essential. The Moon is being affected by the Earth, simply on a a lot a lot smaller scale than anticipated

To make use of the simulation, there are the usual WASD keys, and the mouse to go searching.

#embrace "raylib.h"
#embrace "rlgl.h"
#embrace <math.h>
#embrace <vector>

#outline real_sqrt sqrt
#outline real_pow powf

// Set some bodily values for the simulation
#outline G 6.67408e-11 // [m^3 kg^-1 s^-2]

#outline SOLARMASS 1.989e30 // [kg]
#outline SOLARRADIUS 6.957e8 // [m]

#outline EARTHMASS 5.97219e24 // [kg]
#outline EARTHORBIT 1.496e11 // [m]
#outline EARTHVELOCITY 2.978e4 // [m/s] (Relative to Solar)
#outline EARTHRADIUS 6.371e6 // [m]

#outline MOONMASS 7.34767309e22 // [kg]
#outline MOONORBIT 3.844e8 // [m]
#outline MOONVELOCITY 1.023e3 // [m/s] (Relative to Earth)
#outline MOONRADIUS 1.737e6 // [m]

utilizing namespace std;

namespace engine {
    typedef float actual;

    class Vec3 {
        public:
            // Spatial coordinates
            actual x;
            actual y;
            actual z;

        personal:
            // Padding to make sure 4 phrase alignment
            actual pad;

        public:
            // Default constructor creates a 0 vector
            Vec3() : x(0), y(0), z(0) {}

            // Constructor for when values are handed
            Vec3(const actual x, const actual y, const actual z) : x(x), y(y), z(z) {}

        // Get magnitude of vector
        actual magnitude() const {
            return real_sqrt(x*x + y*y + z*z);
        }

        // Generally it's helpful and quicker to only have the sq. of the magnitude
        actual squareMagnitude() const {
            return x * x + y * y + z * z;
        }

        // Normalize a non-zero vector
        void normalize() {
            actual l = magnitude();
            if (l > 0) {
                (*this) *= ((actual)1)/l;
            }
        }

        // Multiplies vector by given scalar
        void operator *= (const actual scalar) {
            x *= scalar;
            y *= scalar;
            z *= scalar;
        }

        // Returns vector scaled by worth
        Vec3 operator * (const actual worth) const {
            return Vec3(x * worth, y * worth, z * worth);
        }

        // Provides given vector
        Vec3 operator + (const Vec3& v) const {
            return Vec3(x + v.x, y + v.y, z + v.z);
        }

        void operator += (const Vec3& v) {
            x += v.x;
            y += v.y;
            z += v.z;
        }

        // Subtracts given vector
        void operator -= (const Vec3& v) {
            x -= v.x;
            y -= v.y;
            z -= v.z;
        }

        Vec3 operator - (const Vec3& v) const {
            return Vec3(x - v.x, y - v.y, z - v.z);
        }

        // Provides a given scaled vector
        void addScaledVector(const Vec3& v, actual scale) {
            x += (v.x * scale);
            y += (v.y * scale);
            z += (v.z * scale);
        }

        actual operator * (const Vec3& v) const {
            return x * v.x + y * v.y + z * v.z;
        }

        void operator = (const Vec3& v) {
            x = v.x;
            y = v.y;
            z = v.z;
        }

        void clear() {
            x = y = z = 0;
        }
    }; // class Vec3

    class Particle {
        protected:
            // Maintain observe of place and its time derivatives
            Vec3 pos;
            Vec3 vel;
            Vec3 acc;

            // Maintain observe of damping of linear movement
            actual damping;

            /**
             * Holds the inverse of the mass of the particle. It
             * is extra helpful to carry the inverse mass as a result of
             * integration is less complicated, and since in real-time
             * simulation it's extra helpful to have objects with
             * infinite mass (immovable) than zero mass
             * (utterly unstable in numerical simulation).
            */
            actual inverseMass;

            Vec3 forceAccum;

        public:
            Particle() : pos(0, 0, 0), vel(0, 0, 0), acc(0, 0, 0), damping((actual)1.0), inverseMass(0) {};

            Particle(const Vec3 pos, 
                        const Vec3 vel, 
                        const Vec3 acc, 
                        const actual damping, 
                        const actual inverseMass) : pos(pos), vel(vel), acc(acc), damping(damping), inverseMass(inverseMass) {};

            void combine(actual period) {
                // We can't combine particles with infinite or adverse mass
                if (inverseMass <= 0.0f) return;

                assert(period > 0.0);

                // Replace linear place.
                pos.addScaledVector(vel, period);
                pos.addScaledVector(acc, period * period * 0.5);

                //Vec3 resultingAcc = acc;
                //resultingAcc.addScaledVector(forceAccum, inverseMass);
                acc = forceAccum * inverseMass;

                // Impose drag.
                vel *= real_pow(damping, period);

                // Replace linear velocity from the acceleration.
                //vel.addScaledVector(resultingAcc, period);
                vel.addScaledVector(acc, period);

                // Clear forces
                clearAccumulator();
            } // combine()

            // Return place of particle
            Vec3 getPosition() const {
                return pos;
            }

            void clearAccumulator() {
                forceAccum.clear();
            }

            void addForce(const Vec3& f) {
                forceAccum += f;
            }

            bool hasFiniteMass() const {
                return inverseMass > 0.0f;
            }

            actual getMass() const {
                if (inverseMass == 0) {
                    return std::numeric_limits<float>::max();
                } else {
                    return ((actual)1.0)/inverseMass;
                }
            }
    }; // class Particle

    class ParticleForceGenerator {
        public:
            digital void updateForce(Particle *particle, actual period) = 0;
    };

    class ParticleForceRegistry {
        protected:
            // Maintain observe of drive generator and the particle that referred to as for it
            struct ParticleForceRegistration {
                Particle *particle;
                ParticleForceGenerator *fg;
            };

            // Holds record of registrations
            typedef std::vector<ParticleForceRegistration> Registry;
            Registry registrations;

        public:
            // Registers the given drive generator to use to the given particle
            void add(Particle* particle, ParticleForceGenerator* fg) {
                ParticleForceRegistration registration;
                registration.particle = particle;
                registration.fg = fg;
                registrations.push_back(registration);
            }

            // Clear all registrations from the registry
            void clear() {
                registrations.clear();
            }

            // Calls all of the drive turbines to replace the forces of their corresponding particles
            void updateForces(actual period) {
                Registry::iterator i = registrations.start();

                for (; i != registrations.finish(); i++) {
                    i->fg->updateForce(i->particle, period);
                }
            }
    }; // class ParticleForceRegistry

    class ParticlePointGravity : public ParticleForceGenerator {
        Vec3 origin;
        actual mass;

        public:
            ParticlePointGravity(const Vec3& origin, const actual mass)
            : origin(origin), mass(mass) 
            {
            }

            void setOrigin(const Vec3& origin) {
                this->origin = origin;
            }

            void updateForce(Particle* particle, actual period) {
                // Examine if particle has a finite mass
                if (!particle->hasFiniteMass()) return;

                Vec3 drive;

                // Calculate the course of the drive
                Vec3 course = particle->getPosition() - origin;
                actual distance = course.magnitude();
                course.normalize();

                // Calculate the magnitude of the drive
                actual forceMagnitude = -G * particle->getMass() * mass / (distance * distance);
                drive = course * forceMagnitude;
                
                // Apply the drive
                particle->addForce(drive);
            }
    }; // class ParticlePointGravity
}; // namespace engine

utilizing namespace engine;


int major() {
    // Preliminary situations are on the rightmost level of the orbit (wanting down on the system), 
    //   the place the place is barely in x and the rate is barely in z
    Vec3 moon_xi = Vec3(MOONORBIT + EARTHORBIT, 0, 0); // [m]
    Vec3 moon_vi = Vec3(0, 0, MOONVELOCITY + EARTHVELOCITY); // [m/s]
    Vec3 moon_ai = Vec3(0, 0, 0); // [m/s^2]

    Vec3 earth_xi = Vec3(EARTHORBIT, 0, 0); // [m]
    Vec3 earth_vi = Vec3(0, 0, EARTHVELOCITY); // [m/s]
    Vec3 earth_ai = Vec3(0, 0, 0); // [m/s^2]

    Vec3 solGravityOrigin = Vec3(0, 0, 0);
    actual solMass = SOLARMASS; // [kg]

    Particle *earth = new Particle(earth_xi, earth_vi, earth_ai, 1, 1/EARTHMASS);
    Particle *moon = new Particle(moon_xi, moon_vi, moon_ai, 1, 1/MOONMASS);

    // Raylib Initialization
    //--------------------------------------------------------------------------------------
    const int screenWidth = 720;
    const int screenHeight = 450;

    InitWindow(screenWidth, screenHeight, "Djinn - Photo voltaic Orbit Demo");

    // Outline the digital camera to look into our 3d world (place, goal, up vector)
    Digicam digital camera = { 0 };
    digital camera.place = (Vector3){ 15.0f, 5.0f, 0.0f };
    digital camera.goal = (Vector3){ 15.0f, 0.0f, 0.0f };
    digital camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
    digital camera.fovy = 60.0f;
    digital camera.projection = CAMERA_PERSPECTIVE;

    SetCameraMode(digital camera, CAMERA_FIRST_PERSON); // Set a primary particular person digital camera mode
    SetCameraMoveControls(KEY_W, KEY_S, KEY_D, KEY_A, KEY_SPACE, KEY_LEFT_SHIFT);

    SetTargetFPS(60);                           // Set our recreation to run at 60 frames-per-second
    //--------------------------------------------------------------------------------------

    // Time decision
    actual dt = 1e4; // [s]

    // Outline drive registry
    ParticleForceRegistry registry;

    // Outline drive turbines to be utilized to the particle
    ParticlePointGravity* solGravity = new ParticlePointGravity(solGravityOrigin, solMass); // Args: (Vec3) origin, (actual) mass
    ParticlePointGravity* earthGravity = new ParticlePointGravity(earth_xi, EARTHMASS);

    // Register drive turbines with the particle
    registry.add(earth, solGravity);
    registry.add(moon, earthGravity);

    whereas(!WindowShouldClose()) {
        // Replace the forces per loop
        registry.updateForces(dt);

        // Calculate the brand new pos, vel, and acc of the moon and earth
        earth->combine(dt);
        moon->combine(dt);

        // Set the earth gravity's new origin to the brand new place of the earth
        earthGravity->setOrigin(earth->getPosition());

        // Get positions and scale down to suit on display
        Vec3 earth_x = earth->getPosition() * 1e-10; // Scale all the way down to tens of meters
        Vec3 moon_x = moon->getPosition() * 1e-10; // Scale all the way down to tens of meters

        // Convert my Vec3 object to a Raylib Vector3 object
        Vector3 *rl_earth_x = reinterpret_cast<Vector3*>(&earth_x); // Raylib vector for drawing
        Vector3 *rl_moon_x = reinterpret_cast<Vector3*>(&moon_x);

        UpdateCamera(&digital camera);

        BeginDrawing();
            ClearBackground(BLACK);

            BeginMode3D(digital camera);

                DrawGrid(1000, 1.0f);        // Draw a grid

                DrawSphere(*rl_earth_x, 0.25, BLUE); // Draw earth

                DrawSphere(*rl_moon_x, 0.1, GRAY); // Draw moon
            
                DrawSphere((Vector3){0, 0, 0}, 1, YELLOW); // Draw Sol

            EndMode3D();

            DrawRectangle(10, 30, 150, 75, Fade(SKYBLUE, 0.5f));
            DrawRectangleLines(10, 30, 150, 75, BLUE);

            DrawText("Earth:", 20, 40, 10, WHITE);
            DrawText(TextFormat("X: %02.02f", rl_earth_x->x), 20, 55, 10, WHITE);
            DrawText(TextFormat("Y: %02.02f", rl_earth_x->y), 20, 70, 10, WHITE);
            DrawText(TextFormat("Z: %02.02f", rl_earth_x->z), 20, 85, 10, WHITE);

            DrawText("Moon:", 80, 40, 10, WHITE);
            DrawText(TextFormat("X: %02.02f", rl_moon_x->x), 80, 55, 10, WHITE);
            DrawText(TextFormat("Y: %02.02f", rl_moon_x->y), 80, 70, 10, WHITE);
            DrawText(TextFormat("Z: %02.02f", rl_moon_x->z), 80, 85, 10, WHITE);

            DrawFPS(10, 10);

        EndDrawing();
    }

    CloseWindow();

    return 0;
}

NOTE: The flags to compile this code seems to be like : -framework IOKit -framework Cocoa -framework OpenGL <backtick>pkg-config --libs --cflags raylib<backtick>

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments