How to cube a sine/cosine function in processing

Hello,
How do I write cos"raised to the power 3"(t) in my processing code?
I am trying to write this equation :
Capture
Thanks :smiley:

1 Like

x = a * pow(cos(t), 3);

See https://www.processing.org/reference/pow_.html

Please note: angle is in radians

And welcome to the forum!

Great to have you here!

As a function

You could also write a function cube():



void setup() {
  size(800, 600);
}

void draw() {
  println( cube ( 5 ) );
  noLoop();
}

int cube (int in_) {
  return int(pow(in_, 3));
}

Chrisir

3 Likes

I think we’re missing the most obvious way to compute x^3, which is x * x * x, x times x times x.

Raising to an integer power by means of the pow function is not advisable. The pow(x, y) function is used to compute x^y (x raised to y) where x is any positive real number and y any real number, so it actually computes exp(y * log(x)) by means of power series. Thus, when raising to an integer power, it is better to avoid pow as it means more computation and greater error precision in the result.

Maybe the result’s precision and speed of computation are not an issue at all in this case, but I think it is worth mentioning that, as a rule of thumb, using pow for such simple cases is a thing to avoid.

4 Likes

Thanks a ton for the help :smiley:

@trikaphundo thanks, will keep this in mind :+1:

I totally didn’t know that

:wink:

x*x*x is fine for integer cubes. If for some reason you really need high-performance integer exponents in Processing (Java) in general, try this:

// ipow() is a fasts pow() for integers.
// a is the term, b is the exponent.
int ipow (int a, int b) {
  int re = 1;
  while (b > 0) {
    if ((b & 1) == 1) {
      re *= a;
    }
    b >>= 1;
    a *= a;
  }
  return re;
}

Here is a performance test:

void setup() {
  float[] results = new float[10000000];
  int start = millis();
  for (int i = 0; i < results.length; i ++) {
    results[0] = pow((int)random(2,16),54);
  }
  int stop = millis();
  println("pow", stop-start);
  
  int[] iresults = new int[10000000];
  int istart = millis(); 
  for (int i = 0; i < iresults.length; i ++) {
    iresults[0] = ipow((int)random(2,16),54);
  }
  int istop = millis();
  println("ipow", istop-istart);
}

int ipow (int a, int b) {
  int re = 1;
  while (b > 0) {
    if ((b & 1) == 1) {
      re *= a;
    }
    b >>= 1;
    a *= a;
  }
  return re;
}

Output:

pow 922
ipow 165

For integers, ipow() can be significantly faster than pow().

For discussion of different approaches and performance analysis see:

One thing that they don’t note however is that the performance gains may only happen if you are computing different terms each time. If you are just calling fixed terms like pow(2, 64) thousands of times, on the other hand, that may get optimized by the compiler and become really fast no matter what function you use.

Take notice that PApplet.pow() returns Math.pow() downcast to a float:

So there’s an extra call and conversion there.

1 Like

Yes, I know about the binary exponentiation algorithm @jeremydouglass but I didn’t want to frighten him haha, as he was just asking to cube. I appreciate your kindness, thank you :slight_smile:

1 Like

Hello,

Back to your original question…

This was the fastest (667) execution in my tests for your original request:

float angle = random(0, TAU);    
float tmp =  cos(angle);
float cosCubed = tmp*tmp*tmp;

Compared to (1127):

float angle = random(0, TAU);
float cosCubed = cos(angle)*cos(angle)*cos(angle);

Slowest (1275) :

float angle = random(0, TAU);
float cosCubed = pow(cos(angle), 3);

The numbers (ms) were the outcome of a stress test using modified code from @jeremydouglass in this topic.

Processing:

cos();

Is a call to Java:

(float) Math.cos(angle);

You can find Processing cos() and pow() here in the source code if you are adventurous to see what it calls from Java:
https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java

Slightly faster if you call the Java Math functions directly.

:slight_smile:

2 Likes

I wouldn’t advise having the function only work for integers, though, seeing as how we’re working with trig functions.

Absolutely. cos() is not going to be giving you integer arguments. For that @glv’s solution:

float angle = random(0, TAU);    
float tmp =  cos(angle);
float cosCubed = tmp*tmp*tmp;

…is the way to go.

1 Like

The quote of my code (also a link to original) shows:

A cut and past of my code:
float angle = random(0, TAU);
float tmp = cos(angle);
float cosCubed = tmptmptmp;

Formatted code (using editor tools) shows:

float angle = random(0, TAU);    
float tmp =  cos(angle);
float cosCubed = tmp*tmp*tmp;

A picture of my actual code:

The cosCubed result (compare them above) and code in general does always not translate well in a quote or cut and paste.

Oops, thanks for pointing that out. That’s because the forum quote function changed it to plain text and plain text interprets *tmp* as markdown italics, tmp.

The best fix is to add gates ``` – even inside the forum quote. Fixed in my quote above.

1 Like

the formula gives a nice graph when you plot it in 2D in processing

What would be the 3D equivalent?

If you want to orient the 2D curve in 3D space, you could just translate and rotate, then draw as above in 3D.

In the example, x and y are defined independently.

x = a * pow(cos(t), 3);
z = a * pow(cos(t), 2);

You can define z independently in the same way, and you get a 3D shape.

import peasy.*;
PeasyCam cam;
void setup() {
  size(400, 400, P3D);
  cam = new PeasyCam(this, 400);
  strokeWeight(5);
}
void draw() {
  background(128);
  int a = 100;
  for (int t = 0; t<400; t++) {
    float x = a * pow(sin(t), 3);
    float y = a * pow(cos(t), 2);
    float z = a * pow(cos(t), 3);
    point(x, y, z);
  }
}

Sampled coordinates can also be fed into curve functions like curvePoint() or bezierPoint() etc.

1 Like

Hello,

I took notice of the integer steps and had to explore this.

I modified your code to sort this out visually and have integer and float steps for the angles:

//https://discourse.processing.org/t/how-to-cube-a-sine-cosine-function-in-processing/17257/16

//import peasy.*;
//PeasyCam cam;
void setup() 
  {
  size(600, 300, P3D);
  //cam = new PeasyCam(this, 400);
  strokeWeight(5);
  ortho();
  }
  
void draw() 
  {
  background(128);
  int a = 100;
  int steps = 100;
  
  float xAngle = map(mouseX, 0, width, 0, TAU);
  float yAngle = map(mouseY, 0, height, 0, TAU);
  
  // float steps for angle (angle)
  push();
  translate(width/4, height/2);
  rotateX(xAngle);
  rotateY(yAngle);
  stroke(255, 255, 0);
  for (int t = 0; t<steps; t++) 
    {
    float angle = t*(TAU)/steps;  
    float x = a * pow(sin(angle), 3);
    float y = a * pow(cos(angle), 2);
    float z = a * pow(cos(angle), 3);
    point(x, y, z);
    }
  pop();  
   
  // integer steps for angle (t)  
  push();
  translate(3*width/4, height/2);
  rotateX(xAngle);
  rotateY(yAngle);  
  for (int t = 0; t<steps; t++) 
    {
    float x = a * pow(sin(t), 3);
    float y = a * pow(cos(t), 2);
    float z = a * pow(cos(t), 3);
    point(x, y, z);
    }
  pop();    
  }

image

Questions:

  • I replaced PeasyCam with mouse mapping so I could rotate two elements on screen.
    Could I have done this with PeasyCam?

  • I don’t like a large smiley face and have resorted to quotes (see below); is there a better way to do this?

:slight_smile:

1 Like

I tried working further on your 3D sketch.

I made a class to hold one outline (ArrayList of one form).

Then I made an ArrayList of the outlines of different size.

I wanted to connect the different outlines by using QUAD_STRIP to get a nice surface.

On first sight it doesn’t look too bad but when you look at the edges underneath, it’s a mess.

But I can’t get it to work. Is it QUAD_STRIP or TRIANGLE_STRIP ?

Maybe you can take a look. I mark it with ************

When you change showWithFill=true to false you can see the lines better.

Thank you so much!

Chrisir


import peasy.*;
PeasyCam cam;

ArrayList<OneShape> list1 = new ArrayList(); 

ArrayList<PShape> listPShape = new ArrayList();

PShape ps ; 

void setup() {
  size(1400, 1400, P3D);
  background(0);
  cam = new PeasyCam(this, 400);

  list1 = getList();


  for (int i=0; i<list1.size()-1; i++) {

    ps = createShape(); 
    ps.beginShape(QUAD_STRIP);

    // Here true means fill, false means only lines 
    boolean showWithFill=true; 
    if (showWithFill) {
      // fill
      ps.noStroke();
      ps.fill(255, 0, 0);
    } else {
      // only lines 
      ps.noFill();
      ps.stroke(255, 0, 0);
      //
    }//else 

    OneShape os1 = list1.get(i); 
    OneShape os2 = list1.get(i+1); 

    for (int i2=0; i2<os1.listOneShape.size(); i2++) {   // ************************************************

      vertexPV( os1.listOneShape.get(i2)); 
      vertexPV( os2.listOneShape.get(i2)); 
      // vertex(list1.get(i).x, list1.get(i).y, list1.get(i).z);

    }//for // ************************************************************************

    ps.endShape();
    listPShape.add(ps);
    //
  }//for

  avoidClipping();
}//func 

void vertexPV(PVector pv) {
  ps.vertex(pv.x, pv.y, pv.z);
}

void draw() {
  background(0);
  lights(); 

  //for (OneShape os : list1) {
  //  os.display();
  //}//for

  for (PShape ps : listPShape) {
    shape(ps, 0, 0);
  }//for
}//func

//-------------------------------------------------------------------------
// Tools

ArrayList<OneShape> getList() {

  ArrayList<OneShape> listLocal = new ArrayList(); 

  for (int a = 10; a<100; a+=10) {
    OneShape os = new OneShape();
    os.makeOneList(a);
    listLocal.add(os);
  }
  return listLocal;
}

void avoidClipping() {
  // avoid clipping :
  // https : //
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func

// ===========================================================================

class OneShape {

  ArrayList<PVector> listOneShape = new ArrayList(); 
  color col1 = color(random(255), random(255), random(255));

  void makeOneList( float a ) {
    for (int t = 0; t<400; t++) {
      float x = a * pow(sin(t), 3);
      float y = a * pow(cos(t), 2);
      float z = a * pow(cos(t), 3);
      listOneShape.add(new PVector(x, y, z));
    }
  }//func

  void display() {
    stroke(col1); 
    for (PVector pv : listOneShape) {
      point(pv.x, pv.y, pv.z);
    }//for
  }
}
2 Likes

I haven’t inspected the code yet, but keep in mind that this is radial, so

  1. Use @glv 's t<steps where the step radians are computed with PI / TAU (only go around the circle once).
  2. Use TRIANGLE_FAN – it is for radial.

https://processing.org/reference/beginShape_.html

The vertex order for TRIANGLE_FAN that goes all the way around is:

centerpoint, rim0, rim2, rim2… rimN, rim0

2 Likes

My first pass at this using your suggestions.
I will clean it up later!

float lx;
float ly;
float lz;

boolean toggle = true;

void setup() 
  {
  size(500, 500, P3D);
  strokeWeight(1);
  ortho();
  }
  
void draw() 
  {
  background(128);
  int a = 200;
  int steps = 50;
  lights();
  
  float xAngle = map(mouseX, 0, width, 0, TAU);
  float yAngle = map(mouseY, 0, height, 0, TAU);
  
  translate (width/2, height/2);
  
  push();
  rotateX(xAngle);
  rotateY(yAngle);
  
  if (toggle)
    {
    stroke(255, 255, 0);
    noFill();  
    }
  else
    {
    noStroke();
    fill(255, 255, 0);  
    }
  
  for (int t = 0; t<steps; t++) 
    {
    float angle = t*(TAU)/steps;  
    float x = a * pow(sin(angle), 3);
    float y = a * pow(cos(angle), 2);
    float z = a * pow(cos(angle), 3);
    point(x, y, z);
    
    beginShape(TRIANGLE_FAN);
    vertex (0, 0, 0);
    vertex(x, y, z);
    vertex(lx, ly, lz);
    endShape();
    
    lx = x;
    ly = y;
    lz = z; 
    }
  pop();  
  }

void mousePressed()
  {
  toggle = !toggle;
  }

Thanks for inspiring!

And this works:

  beginShape(TRIANGLE);
  for (int t = 1; t<steps; t++) 
    {
    float angle = t*(TAU)/steps;  
    float x = a * pow(sin(angle), 3);
    float y = a * pow(cos(angle), 2);
    float z = a * pow(cos(angle), 3);
    //point(x, y, z);
    
    vertex (0, 0, 0);
    vertex(lx, ly, lz);    
    vertex(x, y, z);

    lx = x;
    ly = y;
    lz = z; 
    }
    endShape();

TRIANGLE_FAN gives this shading:

Your insights please.

:slight_smile: