Дуга с радиусом между 2 точками - PullRequest
0 голосов
/ 27 апреля 2019

Мне нужно выяснить, как нарисовать дугу с OpenGL между 2 точками с заданным радиусом. Есть ли способ сделать это в OpenGL или найти центральную точку, где мне нужно нарисовать дугу, чтобы обе точки получилисвязано с данным радиусом?:)

Прикрепленный скриншот: https://i.imgur.com/LLP78Ak.png

Ответы [ 2 ]

3 голосов
/ 27 апреля 2019

Вот простая, но полная и протестированная программа opengl, которая демонстрирует то, что звучит так, как вы ищете. Обратите внимание, что нет единого ответа на вопрос, что такое дуга между двумя точками на радиусе x, поскольку дуга может изгибаться в любом из двух направлений.

Обратите особое внимание на перегрузку функции second createArc , поскольку она представляет собой ядро ​​ответа, хотя она вызывает first createArc Перегрузка функции для завершения работы.

РЕДАКТИРОВАТЬ: я понял, что я не учел неоднозначность «дуги между двумя углами» в моем предыдущем ответе (дуга от 0 до 90 может быть прямой или наоборот). Я обновил код, чтобы определить, интересуетесь ли вы меньшей или большей дугой.

#define GLEW_STATIC
#define _USE_MATH_DEFINES
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>

const int ARC_VERTEX_COUNT = 100;

// Don't use global variables at home, kids!
GLFWwindow* window;
GLuint shader;
GLint shaderLoc_pos;
GLuint vbo_circle;
GLuint vbo_arc;

float normalizeAngleToSmallestPositive(float angle) {
    while (angle < 0.0) { angle += M_PI*2; }
    while (angle >= M_PI*2) { angle -= M_PI*2; }
    return angle;
}

bool startApp() {
    if (!glfwInit()) {
        return false;
    }
    window = glfwCreateWindow(500, 500, "Hello World", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return false;
    }
    glfwMakeContextCurrent(window);
    glewInit();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glLineWidth(10.0);
    return true;
}

void stopApp() {
    glfwTerminate();
}

void createShader() {
    const char* vsSrc =
        "#version 330 core\n"
        "in vec2 pos; void main() { gl_Position = vec4(pos, 0.0, 1.0); }";
    const char* fsSrc =
        "#version 330 core\n"
        "out vec4 color; void main() { color = vec4(1.0,1.0,1.0,0.5); }";

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vsSrc, nullptr);
    glCompileShader(vs);

    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fsSrc, nullptr);
    glCompileShader(fs);

    shader = glCreateProgram();
    glAttachShader(shader, vs);
    glAttachShader(shader, fs);
    glLinkProgram(shader);

    shaderLoc_pos = glGetAttribLocation(shader, "pos");
}

// Create an arc between two given angles, based on the circle described by the given radius and
// center point
GLuint createArc(float angle1, float angle2, float radius, float x, float y, float useBiggerArc) {
    // Prepare angles
    angle1 = normalizeAngleToSmallestPositive(angle1);
    angle2 = normalizeAngleToSmallestPositive(angle2);
    if (angle1 > angle2) {
        float buffer = angle1;
        angle1 = angle2;
        angle2 = buffer;
    }
    if (useBiggerArc != angle2-angle1 > M_PI) {
        angle1 += M_PI*2;
    }

    // Create opengl geometry
    GLfloat pos[ARC_VERTEX_COUNT * 2];
    for (int i = 0; i < ARC_VERTEX_COUNT; i++) {
        pos[i*2] = sin((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + x;
        pos[i*2+1] = cos((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + y;
    }
    GLuint result;
    glGenBuffers(1, &result);
    glBindBuffer(GL_ARRAY_BUFFER, result);
    glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
    return result;
}

GLuint createCircle(float radius, float x, float y) {
    return createArc(M_PI*0, M_PI*2, radius, x, y, true);
}

// Create an arc between two given points that is based on a circle with the given radius.
GLuint createArc(
    float x1, float y1, float x2, float y2, float radius, bool arcDirection, bool useBiggerArc)
{
    // distance between points
    float distance = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    // halfway point
    float xAverage = (x1+x2)/2.0;
    float yAverage = (y1+y2)/2.0;
    // circle center
    float xCenter = sqrt(radius*radius - distance*distance/4.0) * (y1-y2) / distance;
    float yCenter = sqrt(radius*radius - distance*distance/4.0) * (x2-x1) / distance;
    xCenter = xAverage + (arcDirection ? xCenter : -xCenter);
    yCenter = yAverage + (arcDirection ? yCenter : -yCenter);
    // angles
    float angle1 = atan2(x1-xCenter, y1-yCenter);
    float angle2 = atan2(x2-xCenter, y2-yCenter);
    // create the arc
    return createArc(angle1, angle2, radius, xCenter, yCenter, useBiggerArc);
}

void runMainLoop() {
    while (!glfwWindowShouldClose(window)) {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader);
        glEnableVertexAttribArray(shaderLoc_pos);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_circle);
        glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_arc);
        glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

int main(void) {
    if (startApp())
    {
        createShader();
        vbo_circle = createCircle(0.75, 0.0, 0.0);
        vbo_arc = createArc(0.0, 0.75, 0.75, 0.0, 0.75, false, false);

        runMainLoop();
        stopApp();
        return 0;
    }
    else
    {
        return -1;
    }
}
2 голосов
/ 27 апреля 2019

Мне кажется, это больше математический вопрос.

Если у вас есть координаты двух точек, предположим: formula

и данный радиус равен 'R'

тогда координаты центра, скажем formula1, можно вычислить с помощью

formula2

, где

formula3

formula

должно быть два центра, один для восходящей дуги и другой для нисходящей дуги. другой центр можно найти через

foo

Теперь вы можете найти обратный косинус, используя функцию acos(), включенную в библиотеку <cmath>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...