Extra

Deze pagina bevat uitvoerbare code.

Mandelbrot

Tijdens deze opdracht ga je een programma schrijven om de punten in en rond de mandelbrotverzameling weer te geven en te verkennen.

De vier rekenfuncties hieronder staan in cellen die bij de build worden uitgevoerd, met hun assertions eronder. De functies die een PNG-bestand tekenen staan daaronder als codeblok: die hebben de module png uit mandelbrot.zip nodig en schrijven een bestand weg, dus ze horen thuis op je eigen machine en niet in de build.

De functie mult

def mult(c, n):
    """Vermenigvuldigt c met de positieve integer n, met alleen een lus en optellen."""
    result = 0
    for i in range(n):
        result += c
    return result


assert mult(3, 5) == 15
assert mult(6, 7) == 42
assert mult(1.5, 28) == 42.0

De functie update

def update(c, n):
    """Begint met z = 0, voert z = z**2 + c n keer uit en geeft de laatste z terug."""
    z = 0
    for i in range(n):
        z = z**2 + c
    return z


assert update(1, 3) == 5
assert update(-1, 3) == -1
assert update(-1, 10) == 0

De functie in_mset

def in_mset(c, n):
    """Bepaalt of c binnen de mandelbrotverzameling lijkt te vallen.

    c is de waarde uit de stap z = z**2 + c, en n het aantal keren dat
    die stap hoogstens wordt uitgevoerd.

    Geeft False terug zodra abs(z) groter wordt dan 2, en True als dat
    binnen n stappen niet gebeurt.
    """
    z = 0
    for i in range(n):
        z = z**2 + c
        if abs(z) > 2:
            return False
    return True


c = 0 + 0j
assert in_mset(c, 25) == True
c = 3 + 4j
assert in_mset(c, 25) == False
c = 0.3 + -0.5j
assert in_mset(c, 25) == True
c = -0.7 + 0.3j
assert in_mset(c, 25) == False
c = 0.42 + 0.2j
assert in_mset(c, 25) == True
assert in_mset(c, 50) == False

De functie scale

def scale(pix, pix_max, float_min, float_max):
    """Geeft de floating-pointwaarde terug die bij pixel pix hoort.

    pix is de huidige pixelkolom (of pixelrij), pix_max het totale aantal
    pixelkolommen, en float_min en float_max zijn de onder- en bovengrens
    van het bereik.
    """
    return float_min + (pix / pix_max * (float_max - float_min))


assert scale(100, 200, -2.0, 1.0) == -0.5
assert scale(100, 200, -1.5, 1.5) == 0.0
assert scale(100, 300, -2.0, 1.0) == -1.0
assert scale(25, 300, -2.0, 1.0) == -1.75

De tekenende functies

Deze horen in mandelbrot.py, naast de vier functies hierboven.

# laat deze importregel staan...
from png import *


#
# een testfunctie...
#
def test_fun():
    """Maakt een afbeelding pixel voor pixel en slaat die op als test.png."""
    im = PNGImage(300, 200)  # maak een afbeelding met width=300, height=200

    # Geneste lussen!
    for row in range(200):  # lust over de rijen met lusvariabele row
        for col in range(300):  # lust over de kolommen met col
            if col == row:
                im.plot_point(col, row, (255, 0, 0))

    im.save_file()


def we_want_this_pixel(col, row):
    """Geeft True terug als de pixel op col, row getekend moet worden."""
    if col % 10 == 0 and row % 10 == 0:
        # if col % 10 == 0 or row % 10 == 0:
        return True
    else:
        return False


def test():
    """Laat zien hoe je een PNG-afbeelding maakt en opslaat."""
    width = 300
    height = 200
    image = PNGImage(width, height)

    # maak een lus om wat pixels te tekenen

    for col in range(width):
        for row in range(height):
            if we_want_this_pixel(col, row):
                image.plot_point(col, row)

    # we hebben door alle pixels gelust; nu schrijven we het bestand

    image.save_file()


# test()


def mset():
    """Tekent de mandelbrotverzameling als een afbeelding van 300 bij 200 pixels."""
    NUM_ITER = 50  # aantal updates
    XMIN = -2.0  # de kleinste waarde voor de reële coördinaat
    XMAX = 1.0  # de grootste waarde voor de reële coördinaat
    YMIN = -1.0  # de kleinste waarde voor de imaginaire coördinaat
    YMAX = 1.0  # de grootste waarde voor de imaginaire coördinaat

    width = 300
    height = 200
    image = PNGImage(width, height)

    # maak een lus om wat pixels te tekenen

    for col in range(width):
        for row in range(height):
            # Gebruik scale twee keer:
            #   één keer om het reële deel van c te bepalen (x)
            x = scale(col, width, XMIN, XMAX)
            #   één keer om het imaginaire deel van c te bepalen (y)
            y = scale(row, height, YMIN, YMAX)
            # DAARNA ken je c toe, kies je n en test je:
            c = x + y * 1j
            if in_mset(c, NUM_ITER):
                image.plot_point(col, row, (255, 175, 0))
            else:
                image.plot_point(col, row, (0, 0, 0))

    # we hebben door alle pixels gelust; nu schrijven we het bestand
    image.save_file()


# mset()