Porting a 3D Brownian Motion to Python mode

We all know @GoToLoop is such a wonderful and generous mega-blast of a fellow at the forums, so I always look at his postings, then today I was looking at an example shown at LinkedList vs ArrayList and decided to port it to Python mode :smiley:

On Python we can use deque as a queue.

I hope I have got this right, enjoy!

""" 
Brownian Motion (v3.00)
by Ammon.Owed (2013/Aug)
mod: GoToLoop
port to Python: Villares (2020)
https://discourse.processing.org/t/linkedlist-vs-arraylist/19946/14
Forum.Processing.org/two/discussion/2829/fifo-queue-problem-with-code#Item_1
OpenProcessing.org/sketch/878458
Bl.ocks.org/GoToLoop/145418d1dfb062c7c41a630bce5b8374
"""

from __future__ import division
from collections import deque

TITLE1, TITLE2 = "Brownian Motion     FPS: ", "     Size: "

HAS_MAX_LIMIT = False

DIM, LIMIT, DETAIL, DEPTH = 100, 03000, 1000, 2000
HUE = 1 << 10
HUE_M1 = HUE - 1
FPS, MIN_FPS, SMOOTH = 60, 40, 2
BOLD, AMP = 1.5, 10

points = deque(maxlen=LIMIT)
cam = PVector()
lp = PVector()

paused = False

def setup():
    global canvasRatio, zNear, zFar, frame_rate

    size(950, 600, P3D)

    smooth(SMOOTH)
    frameRate(FPS)

    colorMode(HSB, HUE, 1, 1)
    strokeWeight(BOLD)
    noFill()

    canvasRatio = float(width / height)

    camZ = .5 * height / tan(PI * FPS / 360)
    zNear = camZ / AMP
    zFar = camZ * AMP

    frame_rate = LIMIT << 1


def draw():
    global cam, lp
    # Local-cached & short-named variables:
    fr = round(frame_rate)
    len_p = len(points)
    fc = frameCount

    this.surface.setTitle(TITLE1 + str(fr) + TITLE2 + str(len_p))

    # Recycled or new vector point:
    if len_p != 0 and (not HAS_MAX_LIMIT and fr <= MIN_FPS
                       or HAS_MAX_LIMIT and len_p >= LIMIT):
        np = points.popleft()
    else:
        np = PVector()

    # Interpolated rotating camera aimed at latest added point (tail):
    cam *= .99
    cam.add(PVector.mult(lp, .01, np))

    camera(
        cam.x + sin(.01 * fc) * DETAIL,
        cam.y + cos(8e-3 * fc + 10) * DETAIL,
        cam.z - DEPTH,
        cam.x, cam.y, cam.z,
        0, 1, 0
    )

    # perspective()
    perspective(THIRD_PI, canvasRatio, zNear, zFar)

    # Draw colored curved lines:
    background(0)

    beginShape()
    for p in points:
        fc += 1
        stroke(fc & HUE_M1, 1, 1)
        curveVertex(p.x, p.y, p.z)
    endShape()

    # Generate a new point at specified range:
    np = PVector.random3D(np).mult(DIM)  # pick a new random direction.
    # add that up from latest point.
    np.add(lp)
    # this is now the latest point too.
    lp.set(np)
    # add new point to queue's tail.
    points.append(np)


def mousePressed():
    global paused
    if mouseButton == RIGHT:
        points.clear()
    elif not paused:
        paused = True
        noLoop()
    else:
        paused = False
        loop()
3 Likes

Now a very simplified approach:

""" 
Inspired by 
https://discourse.processing.org/t/linkedlist-vs-arraylist/19946/14
"""

from collections import deque

points = deque(maxlen=150)
paused = False
DIM = 25

def setup():
    size(500, 500, P3D)
    colorMode(HSB)
    noFill()
    points.append(PVector())  # starts with PVector(0, 0, 0)
    
def draw():
    background(0)
    translate(width / 2, height / 2)
    rotateY(frameCount / 100.)

    beginShape()
    for i, p in enumerate(points):
        stroke((frameCount + i) % 256, 255, 255)
        curveVertex(p.x, p.y, p.z)
    endShape()
 
    if not paused:
        v = points[-1]
        n = v + PVector.random3D() * DIM
        points.append(n)
        for p in points:
            p -= n / 30
        
def mousePressed():
    global paused
    if mouseButton == RIGHT:
        points.clear()
        points.append(PVector())
    elif not paused:
        paused = True
        noLoop()
    else:
        paused = False
        loop()
1 Like