在有吸引力的身体上找到加速力

时间:2016-06-30 23:22:23

标签: c++ physics

我有一个围绕着恒星运转的行星的模拟。地球上的力量方程是:

G⋅M<子> 1 ⋅M<子> 2 ⋅(Q <子> 1 -q <子> 2 )/ ||常见<子> 1 -q <子> 2 || 3

其中G是引力常数,M 1 且M 2 是恒星和行星的质量,q 1 -q 2 是两个物体的位置矢量之间的差异。

我已将此等式转换为组件形式

F x =G⋅M 1 ·M 2 ·(x 1 -x 2 )/ ||常见<子> 1 -q <子> 2 || 3

F y =G⋅M 1 ·M 2 ·(y 1 -y 2 )/ ||常见<子> 1 -q <子> 2 || 3

x 1 -x 2 是向量的x分量之间的差异,y 1 -y 2 是向量的y分量之间的差异。

|| q 1 -q 2 || 3 可以重写为sqrt((x 1 -x <子> 2 2 +(Y <子> 1 -y <子> 2 2 3 我们可以改写为((x 1 -x 2 2 +(y 1 -y <子> 2 2 3/2

这是我的代码

    xdif = (planets[0].x - stars[0].x);
    ydif = (planets[0].y - stars[0].y);

    planets[0].ax = -10*xdif / pow((pow(xdif, 2) + pow(ydif, 2)), 1.5);
    planets[0].ay = -10*ydif / pow((pow(xdif, 2) + pow(ydif, 2)), 1.5);

出于某种原因,地球并没有像它应该的那样沿着轨道行进。有谁知道我错了什么?

EDIT :: 忘记提及,所有这些变量都是双精度,语言是c ++

编辑2 ::这是完整的代码

    #define WIN32_LEAN_AND_MEAN

    #include <math.h>
    #include <windows.h>
    #include <stdlib.h>
    #include <string>
    #include <iostream>
    #include <fstream>
    #include <chrono>
    using namespace std;
    #define SCREEN_WIDTH  1920
    #define SCREEN_HEIGHT 1080
    #define LGREY RGB(200,200,200)
    #define BLACK RGB(0, 0, 0)
    #define WHITE RGB(255,255,255)

    WPARAM w;
    HINSTANCE hInst;
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    POINT mousePos;
    int t;
    struct star { double x, y; };
    struct Body { double x, y, vx, vy, ax, ay; };
    star stars[2];
    Body planets[1];
    long newtime= std::chrono::system_clock::now().time_since_epoch().count();
    long oldtime=newtime;
    int signx;
    int signy;
    double force = 0;
    double xdif;
    double ydif;

    void drawCircle(int x, int y, int w, int h, COLORREF insidecolor, COLORREF bordercolor, HDC hdc) {

        HGDIOBJ B1 = CreateSolidBrush(insidecolor);
        HPEN P1 = CreatePen(PS_SOLID, 1, bordercolor);
        SelectObject(hdc, B1);
        SelectObject(hdc, P1);
        Arc(hdc, x, y, x + w, y + h, x - 1, y - 1, x + 1, y + 1);
        DeleteObject(B1);
        DeleteObject(P1);

    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        mousePos = { 1200, 600 };
        WNDCLASSEX wc;
        ZeroMemory(&wc, sizeof(WNDCLASSEX));

        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.lpszClassName = L"WindowClass";
        wc.hbrBackground = CreateSolidBrush(WHITE);

        RegisterClassEx(&wc);

        HWND hWnd = CreateWindowEx(NULL, L"WindowClass", L"Template", WS_OVERLAPPEDWINDOW, 10, 10, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);

        hInst = hInstance;

        //separated by 10 au
        stars[0].x = 0;
        stars[0].y = 0;
        stars[1].x = 10;
        stars[1].y = 0;
        planets[0].x = -5;
        planets[0].y = 0;
        planets[0].vx = 0;
        planets[0].vy = -1;
        planets[0].ax = 0;
        planets[0].ay = 0;

        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);


        MSG msg;
        bool running = TRUE;
        while (running) {
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                if (msg.message == WM_QUIT) {
                    running = FALSE;
                }
            }
        }
        return msg.wParam;
    }
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
        PAINTSTRUCT ps;
        HDC hdc;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);

            planets[0].x += planets[0].vx;
            planets[0].y += planets[0].vy;
            planets[0].vx += planets[0].ax;
            planets[0].vy += planets[0].ay;

            xdif = (planets[0].x - stars[0].x);
            ydif = (planets[0].y - stars[0].y);

            planets[0].ax = -10.0*xdif / pow((pow(xdif, 2) + pow(ydif, 2)), 1.5);
            planets[0].ay = -10.0*ydif / pow((pow(xdif, 2) + pow(ydif, 2)), 1.5);

            for (int i = 0; i < 1; i++) {
                drawCircle(planets[i].x * 50 + 1920 / 2 - 10, planets[i].y + 1080 / 2 - 10, 20, 20, BLACK, BLACK, hdc);
            }
            for (int i = 0; i < 2; i++) {//1920x1080
                drawCircle(stars[i].x*50+1920/2 - 25, stars[i].y+1080/2 - 25, 50, 50, BLACK, BLACK, hdc);
            }
            while (newtime < oldtime + 10000000/60) {//60 frames per second
                newtime = std::chrono::system_clock::now().time_since_epoch().count();
            }
            oldtime = newtime;

            InvalidateRect(hWnd, NULL, TRUE);
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }

        return 0;
    }

使用Visual C ++ 2015,它可以编译如下(使用控制台子系统,适用于测试故障应用程序):

cl orbit.cpp -D UNICODE gdi32.lib user32.lib kernel32.lib /link /subsystem:console /entry:WinMainCRTStartup

2 个答案:

答案 0 :(得分:1)

我使用的公式有问题,我相信分离矢量的正确方法是使用公式C *(q1-q2)/ || q1-q2 || ^ 2

这是代码:

    xdif = (planets[0].x - stars[0].x);
    ydif = (planets[0].y - stars[0].y);

    planets[0].ax = -.01*xdif / pow(hypot(xdif, ydif), 2);
    planets[0].ay = -.01*ydif / pow(hypot(xdif, ydif), 2);

这似乎现在有效,我认为我可以处理一些不稳定因素。非常感谢!

答案 1 :(得分:0)

不是答案,但这不符合评论。

如果您进行以下简单调整,则可以更安全,更准确,更高效,更易读的方式使用<chrono>

auto newtime = std::chrono::system_clock::now();
auto oldtime = newtime;
// ...
using frames = std::chrono::duration<
                                std::chrono::system_clock::rep, std::ratio<1, 60>>;
while (newtime < oldtime + frames{1}) {//60 frames per second
    newtime = std::chrono::system_clock::now();
}
oldtime = newtime;