프로그래밍 언어/OpenGL

[OpenGL] 스플라인_2차 함수 곡선 그리기 (quadratic function)

sujo 2021. 11. 13. 10:00

[OpenGL] 스플라인_2차 함수 곡선 그리기 (quadratic function)

 

개요

: 점 세 개를 지나는 2차 함수 곡선을 그린다.

 

 

 

유도 공식

이때,

  • p(t) : 곡선을 그리는 함수
  • p1 ~ p2 : 각 세개의 점의 좌표
  • t : 0 <= t <= 1 인 실수

 

곡선을 그릴 때는 수많은 점을 이어 곡선처럼 보이는 선을 만드는데 이러한 역할을 t가 해준다.

따라서 코딩할 때는 행렬곱의 순서를 조정해줄 필요가 있다. 그래서 연산 순서는 (1) * ( (2)*(3) ) 이렇게 해줄 것이다.

 

(2) * (3) 을 진행한 결과를 (result)라고 하자. 연산 결과를 임의로 각각 a, b, c라고 가정하자.

 

그럼 p(t)를 아래와 같이 나타낼 수 있다.

다항식을 이런식으로 변형하는 것을 호르너 법칙(Horner's Rule)이라고 한다.

이와 같이 변형한 이유는 프로그램 상에서 정밀도의 문제가 나타나기 때문이다. float는 부동 소수 연산인데, 레지스터 크기를 기준으로 연산 결과를 반올림하거나 절단해버린다. 따라서 최대한 곱셈의 연산을 줄일 것이 요구된다.

아직 2차 함수라서 곱셈 연산을 3번에서 2번으로 줄였지만 차수가 올라갈수록 효율은 커질 것이다.

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <GL/glut.h>
#include <cstring>
using namespace std;
 
GLfloat point[3][2= { {-6.0f, -3.0f}, {-3.0f, 4.0f}, {6.0f, -1.0f} };
GLfloat matrix[3][3= { {2.0f, -4.0f, 2.0f}, {-3.0f, 4.0f, -1.0f}, {1.0f, 0.0f, 0.0f} };
 
void reshape(GLint w, GLint h) {
    glViewport(00, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-10.010.0-10.010.0-1.030.0);
}
 
// 점 찍기
GLvoid drawPoints() {
    glPointSize(7.0f);
 
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
    glBegin(GL_POINTS);
    for (int i = 0; i < 3; i++)
        glVertex2f(point[i][0], point[i][1]);
    glEnd();
}
 
// 점을 기준으로 2차 곡선 spline curve
GLvoid drawCardinal() {
    // init
    GLfloat result[3][2];
    memset(result, 0sizeof(result));
 
    // 행렬 (2) 와 (3) 의 곱
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            result[i][0+= matrix[i][j] * point[j][0];
            result[i][1+= matrix[i][j] * point[j][1];
        }
    }
 
    // 행렬 (1) 과 새로운 행렬 result 의 곱
    GLfloat t = 0.0f;
    GLfloat x, y;
    glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
    glBegin(GL_LINE_STRIP);
    while (t < 1) {
        x = result[2][0+ t * (result[1][0+ result[0][0* t);
        y = result[2][1+ t * (result[1][1+ result[0][1* t);
        glVertex2f(x, y);
        t += 0.01f;
    }
    glEnd();
}
 
GLvoid display() {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
 
    //점 찍기
    drawPoints();
 
    // 점을 기준으로 2차 spline curve
    drawCardinal();
 
    glutSwapBuffers();
}
 
int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500500);
    glutInitWindowPosition(100100);
    glutCreateWindow("Cardinal Splines");
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}
cs