티스토리 뷰

컴퓨터 그래픽스

2. 곡선과 원

Teus 2021. 2. 10. 08:00
728x90
반응형

점과 선, 이번에는 곡선입니다.

 

곡선은 원뿔에서 나옵니다.

 

네. 곡선(쌍곡선, 원, 타원, 한쪽곡선)은 두개의 원뿔로 부터 구할 수 있습니다.

 

원뿔을 빨간 선으로 절단한 경우의 단면

 

이러한 곡선의 Pixel화 역시 직선에 방정식에서 사용한 Bresenham알고리즘을 사용하면

 

화면에 Pixel화 하여 Display하는것이 가능합니다.

 

아래는 이제 곡선을 예로 들어보겠습니다.

 

곡선에 방정식에 적용된 Bresenham알고리즘

곡선의 방정식 역시 X좌표를 이동하면서, next X에서 next Y와 Next Y+1의 사이점을 곡선값과 비교하게 됩니다.

 

이 비교식을 통해서 판별식을 만들고, 만들어진 판별식으로 각 X마다의 Next X에서 Y값을 구하게 됩니다.

 

원의 방정식을 예로 판별식을 봅시다.

 

원의 방정식을 활용한 판별식

이때, 직선과 다르게 곡선은 미분값이 일정하지 않습니다.

 

때문에 X의 위치마다 n의 값을 바꿔가며 판별을 해 줘야합니다.

(물론, 방법을 잘만 사용하면 미분값이 -1~0인 지점을 사용하면 위 방법이 필요 없습니다 :) )

 

Python으로 구현된 원의 Pixel화 소스코드입니다.

class circle:
    def __init__(self, x, y, radius):
        #원의 중심 + 반지름을 저장할 속성을 선언합니다.
        self.c_x = x
        self.c_y = y
        self.r = radius
        #1사분면의 0~45도를 기준으로 계산할 것이기 때문에
        #1사분면의 x의 Max값을 구해줍니다.
        self.this_x = self.c_x + self.r
        self.this_y = self.c_y
        #1사분면에서 원의 45도 위치의 x좌표를 저장합니다.
        self.end_x = round(self.c_x + self.r*(1/pow(2, 1/2)),0)
        self.route_point = []
        #각 축점을 저장합니다.
        self.route_point = self.route_point + [[self.c_x + self.r, self.c_y]]
        self.route_point = self.route_point + [[self.c_x - self.r, self.c_y]]
        self.route_point = self.route_point + [[self.c_x, self.c_y + self.r]]
        self.route_point = self.route_point + [[self.c_x, self.c_y - self.r]]
        
    #Bresenham의 알고리즘과 유사하게 다음 점의 위치를 찾는 판별식을 구성합니다.        
    def j_eq(self,x,y):                
        #이때, 원의 접선의 기울기는 -1~-무한대의 값을 갖습니다(1사분면 0~45도 사이)
        #때문에 x-1에서 y의 값은 y,y+1만이 아니라, y+n, y+n+1사이 중 어떤값을 고르지 결정해야합니다.
        n = 0
        while True:        
            #기존 원의 값이 y+n과 y+n+1에 들어올때까지 n을 증가시켜줍니다.
            j_const = pow(((x-1)-self.c_x),2)+pow((y+(n)-self.c_y),2)-pow(self.r,2)<=0
            j_const_up = pow(((x-1)-self.c_x),2)+pow((y+(n+1)-self.c_y),2)-pow(self.r,2)>=0
            #이제 y+n~y+n+1 사이에 원의 실제 값이 있다면 판별식으로 x-1에서 y의 값을 정합니다.
            if j_const and j_const_up:
                #이 경우 원의 반지름이 원점에서 [x-1, y+n+0.5]보다 긴 것이므로
                #원의 값보다 y+n+0.5가 아래 있으므로, y값은 n+1만큼만 증가합니다.
                if pow(((x-1)-self.c_x),2)+pow((y+(n+0.5)-self.c_y),2)-pow(self.r,2)<0:
                    return [x-1, y+n+1]
                #이 경우 원의 반지름이 원점에서 [x-1, y+n+0.5]보다 짧은 것이므로
                #원의 값보다 y+n+0.5가 위 있으므로, y값은 n만큼만 증가합니다.
                elif pow(((x-1)-self.c_x),2)+pow((y+(n+0.5)-self.c_y),2)-pow(self.r,2)>0:
                    return [x-1, y+n]
            n = n+1
        
    def cal(self):        
        #1사분면의 0~45도 까지만 Point를 계산합니다.
        while self.this_x >= self.end_x:
            #현재의 x,y 값을 통해서 판별식을 진행하고, 판별식 결과를 다시 받습니다
            #이 점들을 모아서 1사분면의 0~45도 사이의 Plot Point를 산출합니다.
            self.this_x, self.this_y = self.j_eq(self.this_x, self.this_y)            
            self.route_point = self.route_point + [[self.this_x, self.this_y]]
            
        #모든 점을 8배화 합니다.(0~45도 사이에서 구한 점을 이용해서, 다른 사분면을 채웁니다.)
        #이때 원의중심이 0,0이 아니라면 해당 Point를 임시로 0,0으로 옮긴 후 계산,
        #다시 원점의 위치를 이동시켜 주면 빠른게 모든 점의위치를 계산할 수 있습니다.
        for i in range(len(self.route_point)):
            ori_point = [self.route_point[i][0]-self.c_x, self.route_point[i][1]-self.c_y]
            self.route_point = self.route_point + [[-ori_point[0]+self.c_x,ori_point[1]+self.c_y]]
            self.route_point = self.route_point + [[ori_point[0]+self.c_x,-ori_point[1]+self.c_y]]
            self.route_point = self.route_point + [[-ori_point[0]+self.c_x,-ori_point[1]+self.c_y]]
            self.route_point = self.route_point + [[ori_point[1]+self.c_x,ori_point[0]+self.c_y]]
            self.route_point = self.route_point + [[-ori_point[1]+self.c_x,ori_point[0]+self.c_y]]
            self.route_point = self.route_point + [[ori_point[1]+self.c_x,-ori_point[0]+self.c_y]]
            self.route_point = self.route_point + [[-ori_point[1]+self.c_x,-ori_point[0]+self.c_y]]

#plot에 사용될 x, y 반지름을 정해줍니다.
c_x, c_y, radius = [30, 10, 108] 

#알고리즘으로 그려진 pixel과 비교할 실제 원(Float값)을 구해줍니다.
def c_eq(x):
    return [[x,c_y + pow(pow(radius,2)-pow((x-c_x),2), 1/2)],[x,c_y - pow(pow(radius,2)-pow((x-c_x),2), 1/2)]]
real_circle = []            
for i in range(c_x-radius-1, c_x+radius+1):
    temp = c_eq(i)
    real_circle = real_circle + [temp[0]]
    real_circle = real_circle + [temp[1]]

#선택된 조건으로 Pixel화된 원을 산출합니다.
test = circle(c_x,c_y,radius)
test.cal()
#시각화하여 두 원을 비교합니다.
import matplotlib.pyplot as plt
plt.figure(figsize = [5,5])
plt.scatter([test.route_point[i][0] for i in range(len(test.route_point))], [test.route_point[i][1] for i in range(len(test.route_point))], s = 10)
plt.scatter([real_circle[i][0] for i in range(len(real_circle))],[real_circle[i][1] for i in range(len(real_circle))], s = 0.5)

728x90
반응형

'컴퓨터 그래픽스' 카테고리의 다른 글

6. 채색 알고리즘(수정중)  (0) 2021.02.15
5. 기하변환 3(복합기하변환, 아핀변환)  (0) 2021.02.13
4. 기하변환2(동차좌표ver)  (0) 2021.02.12
3. 기하변환1(기본기하변환)  (0) 2021.02.11
1. 점과 선  (0) 2021.02.09
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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
글 보관함