├── CompGraph_Midterm_Indra_20195118.py └── README.md /CompGraph_Midterm_Indra_20195118.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from sys import exit 3 | import numpy as np 4 | import math 5 | 6 | width = 800 7 | height = 600 8 | pygame.init() 9 | screen = pygame.display.set_mode((width, height), 0, 32) 10 | 11 | screen = pygame.display.set_mode((width, height), 0, 32) 12 | pygame.display.set_caption("CompGraph_Midterm - Indra Imanuel Gunawan - 20195118") 13 | 14 | # Define the colors we will use in RGB format 15 | BLACK = (0, 0, 0) 16 | WHITE = (255, 255, 255) 17 | BLUE = (0, 0, 255) 18 | GREEN = (0, 255, 0) 19 | RED = (255, 0, 0) 20 | 21 | pts = [] 22 | knots = [] 23 | count = 0 24 | # screen.blit(background, (0,0)) 25 | screen.fill(WHITE) 26 | 27 | # https://kite.com/python/docs/pygame.Surface.blit 28 | clock = pygame.time.Clock() 29 | 30 | def clearAndRedraw(): 31 | #print("tes") 32 | #pygame.draw.rect(screen, WHITE, (0,0,590,height)) 33 | screen.fill(WHITE) 34 | #Line and rects 35 | for i in range(count - 1): 36 | pygame.draw.line(screen, GREEN, pts[i], pts[i+1], 3) 37 | for i in range(count): 38 | pygame.draw.rect(screen, BLUE, (pts[i][0] - margin, pts[i][1] - margin, 2 * margin, 2 * margin), 5) 39 | 40 | #Buttons 41 | lagrangeButton.draw(screen, (0, 0, 0)) 42 | bezierButton.draw(screen, (0, 0, 0)) 43 | hermiteButton.draw(screen, (0, 0, 0)) 44 | cubicSplineButton.draw(screen, (0, 0, 0)) 45 | 46 | #Text 47 | if buttonCheck == 1: 48 | curveType = "Curve Type: Lagrange" 49 | elif buttonCheck == 2 or buttonCheck == -1: 50 | curveType = "Curve Type: Bezier" 51 | elif buttonCheck == 3: 52 | curveType = "Curve Type: Piecewise cubic hermite" 53 | else: 54 | curveType = "Curve Type: Cubic spline" 55 | 56 | font = pygame.font.Font("freesansbold.ttf", 22) 57 | curveText = font.render(curveType, True, BLACK) 58 | screen.blit(curveText, (5,5)) 59 | 60 | #Bezier 61 | def bezier(): 62 | clearAndRedraw() 63 | N = len(pts) 64 | n = N-1 65 | for t in np.arange(0, 1, 0.01): 66 | z = np.zeros(2) 67 | for i in range(N): 68 | z += np.dot((math.factorial(n)/(math.factorial(i)*math.factorial(n-i))) 69 | *((1-t)**(n-i))*(t**i),pts[i]) 70 | 71 | pygame.draw.circle(screen, RED, z.astype(int), 3) 72 | 73 | #Hermite Cubic 74 | def hermiteCubic(): 75 | clearAndRedraw() 76 | N = len(pts) 77 | n = N-1 78 | z = np.array(pts) 79 | c = 0.5 80 | for t in np.arange(0, 1, 0.01): 81 | h1 = (2*(t**3)) - (3*(t**2)) + 1 82 | h2 = (-2 * (t**3)) + (3*(t**2)) 83 | h3 = (t**3) - (2*(t**2)) + t 84 | h4 = (t**3) - (t**2) 85 | for i in np.arange(0, n, 1): 86 | if i==0: 87 | tangent2 = z[i+2] - z[i] 88 | tangent1 = np.zeros(2) 89 | tan2 = np.dot(c, tangent2) 90 | elif (i > 0) and (i < n-1): 91 | tan1 = z[i+1] - z[i-1] 92 | tangent2 = z[i+2] - z[i] 93 | tangent1 = np.dot(c, tan1) 94 | tan2 = np.dot(c, tangent2) 95 | else: 96 | tan1 = z[i+1]-z[i-1] 97 | tangent1 = np.dot(c,tan1) 98 | tan2 = np.zeros(2) 99 | 100 | c_h = np.dot(h1, pts[i]) + np.dot(h2, pts[i+1]) + np.dot(h3, tangent1) + np.dot(h4, tan2) 101 | pygame.draw.circle(screen, RED, c_h.astype(int), 3) 102 | 103 | #Cubic Spline 104 | def cubicSpline(): 105 | clearAndRedraw() 106 | N = len(pts) 107 | n = N-1 108 | 109 | trid = np.identity(N)*4 + np.diag(np.ones(n), 1) + np.diag(np.ones(n), -1) 110 | trid[0][0] = 2 111 | trid[n][n] = 2 112 | 113 | z = np.array(pts) 114 | r = np.zeros((N,2)) 115 | for i in range(N): 116 | if i == 0: 117 | r[i] = z[1]-z[0] 118 | elif i > 0 and i < n: 119 | r[i] = z[i+1]-z[i-1] 120 | else: 121 | r[i] = z[i] - z[i-1] 122 | 123 | w = np.linalg.inv(trid).dot(3*r) 124 | 125 | for t in np.arange(0, 1, 0.01): 126 | for i in range(n): 127 | a = z[i] 128 | b = w[i] 129 | c = np.dot(3, (z[i+1] - z[i]))-np.dot(2, w[i])-w[i+1] 130 | d = np.dot(2, (z[i]-z[i+1]))+w[i]+w[i+1] 131 | yt = a + b*t + c*t*t + d*t*t*t 132 | pygame.draw.circle(screen, RED, yt.astype(int), 3) 133 | 134 | #Lagrange 135 | def lagrange(): 136 | clearAndRedraw() 137 | for t in np.arange(0, len(pts)-1, 0.01): 138 | ptPlt = np.zeros(2, float) 139 | for i in np.arange(0, len(pts), 1): 140 | num, den = 1, 1 141 | for j in np.arange(0, len(pts), 1): 142 | if j != i: 143 | num = num * (t - j) 144 | den = den * (i - j) 145 | ptPlt = ptPlt + np.dot(pts[i], num/den) 146 | pygame.draw.circle(screen, RED, ptPlt.astype(int), 3) 147 | 148 | def drawPolylines(color='GREEN', thick=3): 149 | if (count < 2): return 150 | for i in range(count - 1): 151 | pygame.draw.line(screen, color, pts[i], pts[i+1], thick) 152 | for i in range(count): 153 | pygame.draw.rect(screen, BLUE, (pts[i][0] - margin, pts[i][1] - margin, 2 * margin, 2 * margin), 5) 154 | if(count > 2): 155 | if buttonCheck == 1: 156 | lagrange() 157 | elif buttonCheck == 2 or buttonCheck == -1: 158 | bezier() 159 | elif buttonCheck == 3: 160 | hermiteCubic() 161 | else: 162 | cubicSpline() 163 | 164 | #Button Class 165 | class button(): 166 | def __init__(self, color, x, y, width, height, text=''): 167 | self.color = color 168 | self.x = x 169 | self.y = y 170 | self.width = width 171 | self.height = height 172 | self.text = text 173 | 174 | def draw(self, win, outline=None): 175 | if outline: 176 | pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0) 177 | 178 | pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0) 179 | 180 | if self.text != '': 181 | font = pygame.font.SysFont('comicsans', 30) 182 | text = font.render(self.text, 1, (0, 0, 0)) 183 | win.blit(text, ( 184 | self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2))) 185 | 186 | def isOver(self, pos): 187 | if pos[0] > self.x and pos[0] < self.x + self.width: 188 | if pos[1] > self.y and pos[1] < self.y + self.height: 189 | return True 190 | return False 191 | 192 | # Loop until the user clicks the close button. 193 | done = False 194 | pressed = 0 195 | margin = 6 196 | old_pressed = 0 197 | old_button1 = 0 198 | old_button3 = 0 199 | 200 | selectedPoint = -1 201 | lagrangeButton = button((255,165,0),650,100,120,70,"Lagrange") 202 | bezierButton = button((0,255,0),650,200,120,70,"Bezier") 203 | hermiteButton = button((255,255,0),650,300,120,70,"Hermite") 204 | cubicSplineButton = button((255,255,255),650,400,120,70,"Cubic Spline") 205 | buttonCheck = -1 206 | while not done: 207 | lagrangeButton.draw(screen, (0, 0, 0)) 208 | bezierButton.draw(screen, (0, 0, 0)) 209 | hermiteButton.draw(screen, (0, 0, 0)) 210 | cubicSplineButton.draw(screen, (0, 0, 0)) 211 | 212 | time_passed = clock.tick(30) 213 | 214 | for event in pygame.event.get(): 215 | pos = pygame.mouse.get_pos() 216 | if event.type == pygame.MOUSEBUTTONDOWN: 217 | pressed = -1 218 | if count > 2: 219 | if lagrangeButton.isOver(pos): 220 | buttonCheck = 1 221 | lagrange() 222 | elif bezierButton.isOver(pos): 223 | buttonCheck = 2 224 | bezier() 225 | elif hermiteButton.isOver(pos): 226 | buttonCheck = 3 227 | hermiteCubic() 228 | elif cubicSplineButton.isOver(pos): 229 | buttonCheck = 4 230 | cubicSpline() 231 | elif event.type == pygame.MOUSEBUTTONUP: 232 | pressed = 1 233 | elif event.type == pygame.QUIT: 234 | done = True 235 | else: 236 | pressed = 0 237 | 238 | button1, button2, button3 = pygame.mouse.get_pressed() 239 | x, y = pygame.mouse.get_pos() 240 | pt = [x, y] 241 | 242 | if old_pressed == -1 and pressed == 1 and old_button1 == 1 and button1 == 0: 243 | #Mouse click 244 | if x < 590: 245 | pts.append(pt) 246 | count += 1 247 | pygame.draw.rect(screen, BLUE, (pt[0] - margin, pt[1] - margin, 2 * margin, 2 * margin), 5) 248 | # print("Mouse is clicked") 249 | # print("len:" + repr(len(pts)) + " mouse x:" + repr(x) + " y:" + repr(y) + " button:" + repr( 250 | # button1) + repr(button3) + " old button:" + repr(old_button1) + repr(old_button3) +" pressed:" + repr(pressed) + " old pressed:" + repr(old_pressed) + " add pts ...") 251 | elif old_pressed == -1 and pressed == -1 and old_button1 == 1 and button1 == 1: 252 | #Mouse hold 253 | #print("Mouse is hold") 254 | for i in range(len(pts)): 255 | if((math.isclose(x, pts[i][0], rel_tol=0.05)) and (math.isclose(y, pts[i][1], rel_tol=0.05))): 256 | print("You selected point "+str(i)) 257 | selectedPoint = i 258 | elif old_pressed == 0 and pressed == 0 and old_button1 == 1 and button1 == 1: 259 | #Mouse hold while moving 260 | if selectedPoint != -1: 261 | print("You are moving point "+str(selectedPoint)) 262 | #redraw 263 | #pygame.draw.rect(screen, WHITE, (0,0,590,height)) 264 | screen.fill(WHITE) 265 | pts[selectedPoint][0] = x 266 | pts[selectedPoint][1] = y 267 | elif old_pressed == 1 and pressed == 1 and old_button1 == 0 and button1 == 0: 268 | #print("Mouse is released") 269 | selectedPoint = -1 270 | elif old_pressed == -1 and pressed == 1 and old_button3 == 1 and button3 == 0: 271 | #Right mouse 272 | #print("Right mouse is clicked") 273 | for i in range(len(pts)): 274 | if((math.isclose(x, pts[i][0], rel_tol=0.05)) and (math.isclose(y, pts[i][1], rel_tol=0.05))): 275 | print("You deleted point "+str(i)) 276 | del pts[i] 277 | count -= 1 278 | #pygame.draw.rect(screen, WHITE, (0,0,590,height)) 279 | screen.fill(WHITE) 280 | break 281 | # else: 282 | # print("len:" + repr(len(pts)) + " mouse x:" + repr(x) + " y:" + repr(y) + " button:" + repr( 283 | # button1) + repr(button3) + " old button:" + repr(old_button1) + repr(old_button3) + " pressed:" + repr(pressed) + " old pressed:" + repr(old_pressed)) 284 | 285 | if len(pts) > 1: 286 | drawPolylines(GREEN, 3) 287 | 288 | # Go ahead and update the screen with what we've drawn. 289 | # This MUST happen after all the other drawing commands. 290 | pygame.display.update() 291 | old_button1 = button1 292 | old_pressed = pressed 293 | old_button3 = button3 294 | 295 | pygame.quit() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computer Graphic - Midterm 2 | Computer Graphic Midterm - Indra Imanuel Gunawan / 20195118 3 | 4 | This is my code implementation for the Computer Graphic Midterm. 5 | In this code, I implemented curve drawing using : 6 | 1. Lagrange 7 | 2. Bezier 8 | 3. Piecewise Cubic Hermite Interpolation 9 | 4. Cubic Spline Interpolation 10 | 11 | The code is implemented in python, with the help of pygame library 12 | --------------------------------------------------------------------------------