Computer Graphics & Algorithms

Visualizing complex systems through mathematical computing: from rasterizing primitives to generating recursive fractals.

Python (NumPy) Fractal Geometry Rasterization Linear Algebra

Project Overview

Computer graphics bridges the gap between abstract mathematics and visual perception. This project explores fundamental algorithms for rendering images from code.

It includes a low-level implementation of Rasterization (converting vector shapes into pixels) and a high-performance visualizer for the Mandelbrot Set, optimizing complex number calculations using NumPy vectorization.

Key Concepts Implemented

Vectorization

Optimized the Mandelbrot generation by operating on entire 2D grids of complex numbers simultaneously, replacing slow Python loops with C-optimized NumPy arrays.

Rasterization

Implemented a scan-line algorithm logic to determine whether pixels lie within a mathematically defined triangle, manually handling anti-aliasing and edge cases.

Fractal Recursion

Visualized chaotic behavior where simple iterative rules ($z = z^2 + c$) give rise to infinitely complex boundary structures.

Source Code

1. Mandelbrot Fractal (`p5_hw5.py`)

Generates high-resolution visualizations of the Mandelbrot set.

#!/usr/bin/env python3
#before I begin, I want to say that first I will plot the mandelbrot via pyplot and then make a ps file with the exact scaling (image) of the part that I zoomed in the pyplot.

import numpy as np
import matplotlib.pyplot as plt

#function of mandelbrot

def mandelbrot(c, max_iter):
    z = 0
    for n in range(max_iter):
        if abs(z) > 2:
            return n
        z = z*z +c
    return max_iter

def mandelbrotset(xmin, xmax, ymin,ymax, width, height, max_iter):
    x = np.linspace(xmin,xmax, width)
    y = np.linspace(ymin, ymax, height)
    mset = np.zeros((height,width))
    
    for i in range(height):
        for j in range(width):
            c = complex(x[j],y[i])
            mset[i,j] = mandelbrot(c, max_iter)
    return mset

width, height = 512, 384
max_iter = 250
xmin, xmax, ymin, ymax = -0.74625,-0.73875,0.10125,0.11375

print("Generating Mandelbrot: ")
print(f"Re axis: [{xmin},{xmax}] (range: {xmax - xmin})")
print(f"Im axis: [{ymin},{ymax}] (range: {ymax - ymin})")
print(f"Grid: {width}x{height}, Max iterations: {max_iter}\n")

mandelbrot_image = mandelbrotset(xmin,xmax,ymin,ymax,width,height,max_iter)
plt.imshow(mandelbrot_image, extent=[xmin,xmax,ymin,ymax], cmap = 'hot')
plt.colorbar()
plt.title('mandelbrot visualization')
plt.xlabel('Re(c)')
plt.ylabel('Im(c)')
plt.savefig("p5_hw5.ps")
plt.show()

2. Triangle Rasterization (`p4_hw5.py`)

Low-level implementation of drawing a triangle pixel-by-pixel.

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

X, Y = 512, 409
lw = 20
base_x1, base_y1 = 0, 0
base_x2, base_y2 = 400, 0
top_x, top_y = 400, 300
slope = 3 / 4
color = (0, 0, 255)        
bg_color = (255, 255, 255) 
offset = 48
half_lw = lw//2
total_offset = offset+half_lw
save_name = "p4_hw5_rt345_raster.tif"

hyp_thickness = int(lw/0.8) #cos of angle is 0.8)

#Setting white canvas
pvals = np.full((X, Y, 3), bg_color, dtype='uint8')

# Draw
for x in range(X):
    for y in range(Y):
        rel_x = x-total_offset
        rel_y = y-total_offset
        y_hyp = slope * rel_x
        if (0 <= rel_y <= lw) or (y_hyp - hyp_thickness <= rel_y <= y_hyp) or (top_x - lw <= rel_x <= top_x):
            if rel_y <= slope * rel_x and rel_x <= top_x and rel_y >= 0:
                pvals[x, y, :] = color

plotarr = np.flipud(pvals.transpose(1, 0, 2))
f1, ax1 = plt.subplots()
ax1.imshow(plotarr, interpolation='none')
ax1.axis('off')
plt.show()

# Save image
im = Image.fromarray(plotarr, 'RGB')
im.save(save_name)
print(f'Image saved to {save_name}')
input("\nPress Enter to exit...\n")