Маятник : Продвинутое интегрирование

Используем бибилотеку Boost.Numeric.Odeint для интегрирования динамическиx уравнений.

Проект программы

Файл CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)

project(advanced
    VERSION 0.1
    LANGUAGES CXX)

find_package(glfw3 REQUIRED)
find_package(OpenGL REQUIRED)
find_package(glm REQUIRED)
find_package(Boost REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME} glfw OpenGL::GL glm)
set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIR}")

Код программы

Файл main.cpp:

#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <boost/numeric/odeint/integrate/integrate.hpp>

#include <vector>

static GLFWwindow *window   = nullptr;

static double length        = 1.0;
static double radius        = 0.05;
static double angle         = glm::radians(45.0);

static double angleVelosity = 0.0;

static double gravityAcceleration = 9.81;

static double lastTime      = 0.0;
static double currentTime   = 0.0;

void ode(const std::vector<double> &x, std::vector<double> &dxdt, const double /*t*/)
{
    dxdt[0] = x[1];
    dxdt[1] = -gravityAcceleration / length * glm::sin(x[0]);
}

void integrate(double delta)
{
    std::vector<double> x(2);

    x[0] = angle;
    x[1] = angleVelosity;

    boost::numeric::odeint::integrate(ode, x, 0.0, delta, glm::min(delta, 0.01));

    angle = x[0];
    angleVelosity = x[1];
}

void draw()
{
    glLineWidth(1.0f);
    glColor3f(1.0f, 1.0f, 1.0f);
    glm::mat4x4 rot = glm::rotate(glm::mat4x4(1.0f)
                                , static_cast<float>(angle)
                                , glm::vec3(0.0f, 0.0f, 1.0f));
    glm::vec4 pos = rot * glm::vec4(0.0f, static_cast<float>(-length), 0.0f, 1.0f);
    glBegin(GL_LINES);
        glVertex3f(0.0f, 0.0f, 0.0f);
        glVertex3fv(glm::value_ptr(pos));
    glEnd();
    glColor3f(1.0f, 0.0f, 0.0f);
    int numSec = 36;
    glm::mat4x4 rotSec = glm::rotate(glm::mat4x4(1.0f)
                                    , glm::radians(360.0f / numSec)
                                    , glm::vec3(0.0f, 0.0f, 1.0f));
    glm::vec4 posLast(static_cast<float>(radius), 0.0f, 0.0f, 1.0f);
    glBegin(GL_TRIANGLES);
    for(int i = 0; i < numSec; ++i)
    {
        glm::vec4 posNext = rotSec * posLast;
        glVertex3fv(glm::value_ptr(pos));
        glVertex3fv(glm::value_ptr(pos + posLast));
        glVertex3fv(glm::value_ptr(pos + posNext));
        posLast = posNext;
    }
    glEnd();
}

void frame()
{
    currentTime = glfwGetTime();

    integrate(currentTime - lastTime);

    lastTime = currentTime;

    glClear(GL_COLOR_BUFFER_BIT);

    draw();

    glfwSwapBuffers(window);

    glfwPollEvents();
}

int main()
{
    if (!glfwInit())
    {
        return 1;
    }

    glfwWindowHint(GLFW_SAMPLES, 4);
    window = glfwCreateWindow(600, 600, "Маятник: Графическое представление", nullptr, nullptr);
    if (!window)
    {
        return 2;
    }

    glfwMakeContextCurrent(window);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    lastTime = glfwGetTime();

    while (!glfwWindowShouldClose(window))
    {
        frame();
    }

    glfwTerminate();

    return 0;
}

Запуск программы

При запуске программа интегрирует динамические уравнения и отрисовывает геометрию маятника в вычисленном положении.