Interpreting Formulas into P5

Forgive me for the super basic-ness of this question, but I've been scouring for good resources on this for weeks and running out of options. Perhaps it's so basic that nobody has bothered to lay it out, but I'm struggling a bit with it.

Basically, I'm trying to figure out the best method for representing an equation in P5 would be. For example, given the equations (whether Cartesian, polar or parametric) for drawing a cardioid for example ( http://www.wolframalpha.com/input/?i=cardioid ) - how would you actually interpret this and draw this in P5?

My attempts have been to use a for loop and try to create points of regular intervals that are run through the equation, but I have yet to be successful. The only success I've had was reverse engineering a bit of code from a CodePen that uses the method described on that Wolfram Alpha page for creating cardioids by drawing circles based around a fixed point, but I have yet to get my head around trying to draw the envelope of that shape with a curve or something like that - which I think would be ideal.

Perhaps P5/Processing is not the right tool for the job? I'm leaning towards thinking that maybe I'm just not thinking about how to interpret this the right way though, so if anybody has experience with adapting parametric formulas etc into P5 and could shine a little light to point me in the right direction I'd be very appreciative.

Answers

  • Answer ✓

    Here is an example, that draws points based on your equations:

    size(400, 400);
    translate(width/2, height/2);
    
    float interval = 0.01;
    float a = 100;
    
    for (float t =0; t< TWO_PI; t+=interval) {
      float x = a * (1-cos(t)) * cos(t);
      float y = a * sin(t) * (1-cos(t));
      point(x, y);
    }
    
  • Awesome, thank you so much Benja, that's exactly along the lines of what I was trying to do, I wasn't basing my interval around radiating around a circle, makes sense now (dusting off my math as I dive into this stuff). Much appreciated.

    Is there a method you know of for interpreting a formula like this into a path or something along those lines, series of curves etc. Like a series of steps to plot control points from a formula?

    I ask because I'm curious if there's a way to smoothly transition between different formulas. I can make a button that will transition between this and, say, a formula for a figure 8 or a rose, but it will just redraw. Whereas with a path I feel like I could possibly find a method for more smoothly transitioning between them, if that makes sense.

    Getting off on a bit of a tangent on that apologies. Very much appreciate the clarity you provided on this.

  • edited November 2015 Answer ✓

    Cardioid p5.js version: http://p5ide.HerokuApp.com/_/563ec11249d4ce03006af094

    // Cardioid (v2.1.1)
    // Benja & GoToLoop (2015-Nov-07)
    
    // www.WolfRamAlpha.com/input/?i=cardioid
    // forum.Processing.org/two/discussion/13433/interpreting-formulas-into-p5
    // p5ide.Herokuapp.com/_/563ec11249d4ce03006af094
    
    const DIAM = 100, STEP = .01, 
          BLUE = Object.freeze([0, 0, 0xFF, 0xFF]);
    
    var cx, cy;
    
    function setup() {
      createCanvas(500, 400);
      noLoop();
      cx = width>>1, cy = height>>1;
    }
    
    function draw() {
      background(0350);
    
      for (var costT, tDiam, x, y, t = 0; t < TAU; t += STEP) {
        cosT = cos(t), tDiam = (1 - cosT) * DIAM;
    
        x = round(cosT   * tDiam) + cx;
        y = round(sin(t) * tDiam) + cy;
    
        set(x, y, BLUE);
      }
    
      updatePixels();
    }
    
  • Thanks Benja and GoToLoop - Loop there are definitely some aspects of your example I don't quite follow so I've got to dig into a little more, much appreciated on both though. I realized that instead of using points I could use them as vertices in a shape path to get the path/shape output I was looking for, and with 0.01 resolution that actually works well even if they don't technically curve properly.

    Now I'm on to working out how to 'tween' between two such formulas/shapes (I just learned this term yesterday, that was the 'smooth transitioning' idea I was referring to earlier). Going to try and dig into the ijeoma library today and see if that helps. Anyway, off on a tangent again, thanks for the help!

  • If you need a simple transition between two values, you could use lerp() or map(). Example:

    float interval = 0.01;
    float a = 100;
    float b = 20;
    
    void setup() {
      size(400, 400);
    }
    
    void draw() {
      background(255);
      translate(width/2, height/2);
    
      for (float t =0; t< TWO_PI; t+=interval) {
        float x1 = a * (1-cos(t)) * cos(t);
        float y1 = a * sin(t) * (1-cos(t));
    
        float x2 = a * (cos(t)*cos(t)) + b* cos(t);
        float y2 = a * cos(t)*sin(t) + b *sin(t);
    
        float x = lerp(x1, x2, (float)(frameCount%200)*0.005);
        float y = lerp(y1, y2, (float)(frameCount%200)*0.005);
        point(x, y);
      }
    }
    

    I don't know this ijeoma-library, maybe it's a better choice,

  • ... there are definitely some aspects of your example I don't quite follow so I've got to dig into a little more, ...

    Just ask what is then. O:-)

  • Just gotoloops bad programming style...

    Not readable.....

    A shame.....

  • Thanks again GoToLoop and Benja, really appreciate the help. Lerp is exactly what I was looking for. I've got that implemented well in my sketch, but I've been racking my brain for the past couple hours trying to figure out a way to get it to stop the loop once it's finished interpolating to one shape. I thought if I populated all the vertices into arrays then triggered noLoop at the end of the array that would work, but it just doesn't start when I try to implement that - here's a section of what I'm working on (verticesC = the points for a cardioid, verticesF = the points for a figure 8 shape). If I remove the noLoop call it works, but obviously just keeps looping.

    beginShape();
    for (var i = 0; i < verticesC.length; i++) {
                    x = lerp(verticesC[i][0], verticesF[i][0], (frameCount%500)*0.002);
                    y = lerp(verticesC[i][1], verticesF[i][1], (frameCount%500)*0.002);
                    vertex(x,y);
                    if (i === (verticesC.length - 1)){
                      noLoop();
                    }
                }
        endShape();
    

    Really thought I could figure it out once I had the lerp part worked out, but I'm stuck again.

    If I can figure out a way to trigger it stop once it's fully interpolated to one shape, then it should be straightforward to assign lerp'ing to one shape or another to buttons or other triggers.

    Is there a standard method for smoothly 'lerp'ing from one set of parameters to another and then sticking there that I'm missing?

    Sorry for all these questions, trying to work this out as much on my own as I can, I really appreciate the help.

  • edited November 2015

    noLoop() simply turns off the auto-calling of draw().
    In no way it can magically shutdown an executing function.
    In order to prematurely quit any function we call return.

    If you look at my own example, you can spot I've used noLoop() within setup().
    But you'll also notice that draw() still happens, right?
    But once draw() finishes running, sketch halts as it should and doesn't update latest frame. ;;)

  • I was all set to post a long reply with more questions but I figured out my problem - I was trying to stop the animation from looping when the entire lerp amount I was using (taken from Benja's example) was based around the frame rate, and thus was always going to loop. Realized I just needed to make some functions to smoothly adjust the lerp amount between 0 and 1 to go back and forth and make the animation a 'one shot' to speak. I think I can work out the rest of my sketch from here. Good thing too, I've been at it all day and was starting to go a little @-) -- thanks so much for the help, very much appreciated, great to not feel like I'm just alone smacking my head against a wall when I'm trying to build stuff!

  • edited November 2015

    Just a last tip: We can view draw() itself as a big loop. And frameCount as its iterator counter:
    https://Processing.org/reference/frameCount.html

Sign In or Register to comment.