Vertex, loop and draw along a vertex path

Hi,
I’m trying to adapt the code which has been written in java by Daniel Shiffman on his youtube channel into P5.js and I’ve met some problems. The loop which I used to draw the shape doesn’t work properly. In object which I created a vector values x,y and z are still 0 ( 0: Vector {vx: 0, vy: 0, vz: 0}
1: Vector {vx: 0, vy: 0, vz: 0} etc. etc). Where am I wrong?

This is a video which I mentioned -> https://www.youtube.com/watch?v=r6YMKr1X0VA&t=104s

This is my code:

let beta;
let arr =[];
function setup() {
      createCanvas(400, 400, WEBGL);  
}

function draw(){
      beta = 0;
      background(0);
      translate(width/2, height/2);
            let r = 250*(0.8 * 1.6 * sin(6 * beta));
            let theta = 2 * beta;
            let phi = 0.6 * PI * sin(12 * beta);

            let x = r * cos(phi) * cos(theta);
            let y = r * cos(phi) * sin(theta);
            let z = r * sin(phi);

            arr.push(new Vector(x,y,z));
            
            beta += 0.01;
            stroke(255);
            strokeWeight(3);
            noFill();
            beginShape();
            for(let v of arr) {
                  vertex(v.vx, v.vy, v.vz);
            }
     
      endShape();       
}

class Vector {
      constructor(vx, vy, vz) {
            this.vx = vx;
            this.vy = vy;
            this.vz = vz;
      }
}
1 Like

Even though Java & JS share most of their syntaxes, there are still some important differences.

A peculiar 1 of them is which default value is assigned to a newly created variable or property.

Java assigns a different initial value to a newly field depending on its declared datatype:
Docs.Oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

But not JS (Python the same)! Default value is always undefined (None to Python).

So just after let beta;, variable beta is equal to undefined.
And any math operations w/ undefined result NaN!

2 Likes

I did some refactoring to the original Java Mode version. :coffee:
You can watch it running online here: :running_man:

OpenProcessing.org/sketch/608725

The online version got a bug though: strokeWeight() is completely ignored by vertex()! :space_invader:

But it runs 100% correctly in the PDE (Processing’s IDE) though. :smirk:

“Knot3D.pde”:

/**
 * 3D Knot (2017/Dec)
 * Daniel Shiffman
 * https://YouTu.be/r6YMKr1X0VA
 *
 * Mod GoToLoop (v1.0.3) (2018/Oct/16)
 * https://OpenProcessing.org/sketch/608725 (pjs)
 * https://OpenProcessing.org/sketch/608726 (p5js)
 *
 * https://Discourse.Processing.org/t/
 * vertex-loop-and-draw-along-a-vertex-path/4545/3
 */

/**
 * http://PaulBourke.net/geometry/knots/
 * Knot 4 (1992/Oct):
 *
 * r(beta) = 0.8 + 1.6 * sin(6.0 * beta)
 * theta(beta) = 2 * beta
 * phi(beta) = 0.6 * pi * sin(12.0 * beta)
 *
 * x = r * cos(phi) * cos(theta)
 * y = r * cos(phi) * sin(theta)
 * z = r * sin(phi)
 */

import java.util.List;
final List<Knot> knots = new ArrayList<Knot>();

static final float
  ANGLE_STEP = .02, BETA_STEP = .01, 
  MAG = 100.0, SEGS_LIMIT = PI + BETA_STEP, 
  PI_DOT_6 = PI * .6;

float angle, beta;
boolean paused;

void setup() {
  size(600, 600, P3D);
  smooth(8);

  colorMode(HSB);
  noFill();
  strokeWeight(8.0);
}

void draw() {
  background(0);
  translate(width>>1, height>>1);
  rotateY(angle += ANGLE_STEP);

  if (beta <= SEGS_LIMIT)  addKnot();
  beta += BETA_STEP;

  beginShape();
  for (final Knot k : knots) {
    stroke(k.c);
    vertex(k.v.x, k.v.y, k.v.z);
  }
  endShape();
}

void mousePressed() {
  if (paused ^= true)  noLoop();
  else                 loop();
}

void keyPressed() {
  mousePressed();
}

void addKnot() {
  final float
    r = MAG * (.8 + 1.6 * sin(6.0 * beta)), 
    theta = 2.0 * beta, 
    phi = PI_DOT_6 * sin(12.0 * beta), 
    rCosPhi = r * cos(phi), 

    x = rCosPhi * cos(theta), 
    y = rCosPhi * sin(theta), 
    z = r * sin(phi);

  final Knot knot = new Knot(x, y, z);
  knots.add(knot);
  println(knots.size() + ": " + knot);
}

class Knot {
  final PVector v;
  final color c;

  Knot(final float x, final float y, final float z) {
    this(new PVector(x, y, z));
  }

  Knot(final PVector vec) {
    c = color((v = vec).mag(), 255, 255);
  }

  String toString() {
    return "Vec: " + v + "   \tHSB: " + c;
  }
}
1 Like

And while I was at it, I did a Python Mode version too: :snake:

“Knot3D.pyde”:

"""
 * 3D Knot (2017/Dec)
 * Daniel Shiffman
 * https://YouTu.be/r6YMKr1X0VA
 *
 * Mod GoToLoop (v1.0.3) (2018/Oct/16)
 * https://OpenProcessing.org/sketch/608725 (pjs)
 * https://OpenProcessing.org/sketch/608726 (p5js)
 *
 * https://Discourse.Processing.org/t/
 * vertex-loop-and-draw-along-a-vertex-path/4545/4
"""

"""
 * http://PaulBourke.net/geometry/knots/
 * Knot 4 (1992/Oct):
 *
 * r(beta) = 0.8 + 1.6 * sin(6 * beta)
 * theta(beta) = 2 * beta
 * phi(beta) = 0.6 * pi * sin(12 * beta)
 *
 * x = r * cos(phi) * cos(theta)
 * y = r * cos(phi) * sin(theta)
 * z = r * sin(phi)
"""

ANGLE_STEP, BETA_STEP = .02, .01
MAG, SEGS_LIMIT = 100.0, PI + BETA_STEP
PI_DOT_6 = PI * .6

angle = beta = 0.0
paused = False

knots = []

def setup():
    size(600, 600, P3D)
    smooth(8)

    colorMode(HSB)
    noFill()
    strokeWeight(8.0)


def draw():
    global angle, beta

    background(0)
    translate(width>>1, height>>1)
    rotateY(angle)
    angle += ANGLE_STEP

    beta <= SEGS_LIMIT and addKnot()
    beta += BETA_STEP

    with beginShape():
        for k in knots:
            stroke(k.c)
            vertex(k.v.x, k.v.y, k.v.z)


def mousePressed():
    global paused
    paused ^= True
    noLoop() if paused else loop()


def keyPressed(): mousePressed()


def addKnot():
    r = MAG * (.8 + 1.6 * sin(6 * beta))
    theta = 2 * beta
    phi = PI_DOT_6 * sin(12 * beta)
    rCosPhi = r * cos(phi)

    x = rCosPhi * cos(theta)
    y = rCosPhi * sin(theta)
    z = r * sin(phi)

    knot = Knot(x, y, z)
    knots.append(knot)
    print '%d: %s' % (len(knots), knot)


class Knot:
    def __init__(k, *vec):
        k.v = vec[0] if len(vec) is 1 else PVector(*vec)
        k.c = color(k.v.mag(), 255, 255)


    def __str__(k): return 'Vec: %s   \tHSB: %d' % (k.v, k.c)
3 Likes

And finally the “3D Knot” p5js version. Watch it online below: :grin:
OpenProcessing.org/sketch/608726

However, there’s a worse bug in it: the last stroke() determines the color for all vertex()! :-1:

“index.html”:

<!DOCTYPE html>

<meta charset=utf-8>
<meta name=viewport content=width=device-width,initial-scale=1>

<script async src=https://cdn.JsDelivr.net/npm/p5/lib/p5.js></script>
<script defer src=sketch.js></script>

“sketch.js”:

/**
 * 3D Knot (2017/Dec)
 * Daniel Shiffman
 * https://YouTu.be/r6YMKr1X0VA
 *
 * Mod GoToLoop (v1.0.1) (2018/Oct/16)
 * https://OpenProcessing.org/sketch/608725 (pjs)
 * https://OpenProcessing.org/sketch/608726 (p5js)
 *
 * https://Discourse.Processing.org/t/
 * vertex-loop-and-draw-along-a-vertex-path/4545/5
 */

/**
 * http://PaulBourke.net/geometry/knots/
 * Knot 4 (1992/Oct):
 *
 * r(beta) = 0.8 + 1.6 * sin(6 * beta)
 * theta(beta) = 2 * beta
 * phi(beta) = 0.6 * pi * sin(12 * beta)
 *
 * x = r * cos(phi) * cos(theta)
 * y = r * cos(phi) * sin(theta)
 * z = r * sin(phi)
 */

"use strict";

const π = Math.PI, ANGLE_STEP = .02, BETA_STEP = .01,
      MAG = 100.0, SEGS_LIMIT = π + BETA_STEP,
      PI_DOT_6 = π*.6,
      knots = []

let α = 0.0, β = 0.0, paused = false, bg

function setup() {
  createCanvas(600, 600, WEBGL).mousePressed(togglePause)
  bg = color(0)
  colorMode(HSB).strokeWeight(8.0).noFill()
}

function draw() {
  background(bg).rotateY(α += ANGLE_STEP)

  β <= SEGS_LIMIT && addKnot()
  β += BETA_STEP

  beginShape()
  for (const { c, v } of knots)  stroke(c).vertex(v.x, v.y, v.z)
  endShape()
}

function togglePause() {
  (paused = !paused)? noLoop() : loop()
}

function keyPressed() {
  togglePause()
}

function addKnot() {
  const r = MAG * (.8 + sin(6*β)*1.6),
        θ = 2*β, φ = PI_DOT_6 * sin(12*β),
        rCosφ = r * cos(φ),
        x = rCosφ * cos(θ), y = rCosφ * sin(θ), z = r * sin(φ),
        knot = new Knot(x, y, z)

  knots.push(knot)
  console.log(knots.length + ':', knot)
}

class Knot {
  constructor(...vec) {
    this.v = vec.length === 1? vec[0] : createVector(...vec)
    this.c = color(this.v.mag(), 100, 100)
  }
}
2 Likes

Thanks. This is exactly what I am looking for.