How do I create sinusoidal movement at an angle?

edited September 2014 in Questions about Code

This one's been eating away at me! Seems so simple but I can't get it to work. So if I have a particle traveling at 3 pixels per frame at a 60 degree angle away from the center point of the sketch, the code looks something like this (this is a simplified version):

stroke(255);
float velocity = 3;
float angle = 60;
PVector position = (width/2, height/2);

void draw() {
    background(0);
    position.x += cos(angle) * velocity;
    position.y += sin(angle) * velocity;
    point(position.x, position.y);
}

However, when I try to make the particle oscillate up and down at right angles from the current trajectory, I can't seem to make it work! This is what I tried. It seemed to make sense but it doesn't give me a proper sine wave:

stroke(255);
float velocity = 3;
float angle = 60;
float t = 0; // Time
float amplitude = 20; // Amplitude of sine wave
PVector position = (width/2, height/2);

void draw() {
    background(0);
    position.x += cos(angle) * velocity;
    position.y += sin(angle) * velocity;
    position.x += (cos(angle +90)) * sin(t) * amplitude;
    position.y += (sin(angle +90)) * sin(t) * amplitude;
    point(position.x, position.y);
}

My math skills aren't the best, so I'm hoping I'm missing something basic and that an intelligent forum-goer can assist me! Thank you in advance!

Answers

  • Answer ✓

    "this is a simplified version"
    It wouldn't take much more work to make a "runnable" version...

    float velocity = 3;
    float angle = 60;
    PVector position;
    
    void setup()
    {
      size(800, 800);
      stroke(255);
      position = new PVector(width/2, height/2);
    }
    
    void draw() 
    {
      background(0);
      position.x += cos(angle) * velocity;
      position.y += sin(angle) * velocity;
      point(position.x, position.y);
    }
    

    If I understand correctly your request, you must add an orthogonal vector to the current position of the vector.

    float velocity = 1;
    float angle = 60;
    float t = 0; // Time
    float amplitude = 20; // Amplitude of sine wave
    PVector center, position;
    
    void setup()
    {
      size(800, 800);
      stroke(255);
      center = new PVector(width/2, height/2);
      position = center.get();
    }
    
    void draw() 
    {
      background(0);
      position.x += cos(angle) * velocity;
      position.y += sin(angle) * velocity;
      PVector a = perpendicular(PVector.sub(position, center, null));
      a.normalize();
      a.mult(sin(t) * amplitude);
      point(position.x + a.x, position.y + a.y);
      t += PI / 12;
      println("--");
    }
    
    PVector perpendicular(PVector v)
    {
      return new PVector(-v.y, v.x);
    }
    
  • edited September 2014

    I've refactored @PhiLho's example for better performance! :ar!

    // forum.processing.org/two/discussion/7103/
    // how-do-i-create-sinusoidal-movement-at-an-angle
    
    // by Hendeca, mods PhiLho & GoToLoop - 2014/Sep
    
    static final float VEL = 1.5, ANG = 60.0, AMP = 30.0;
    static final float VEL_X = VEL*cos(ANG), VEL_Y = VEL*sin(ANG);
    float t;
    
    final PVector center  = new PVector(), pos = new PVector();
    final PVector perpend = new PVector();
    
    void setup() {
      size(600, 400, JAVA2D);
      smooth(4);
      frameRate(60);
    
      strokeWeight(4);
      stroke(-1);
    
      center.set(width, height*.75);
    }
    
    void draw() {
      pos.add(VEL_X, VEL_Y, 0);
      if (pos.x<0 | pos.y<0)  pos.set(center);
    
      PVector.sub(pos, center, perpend).set(-perpend.y, perpend.x);
      perpend.setMag(AMP*sin(t += PI/12.0));
    
      background(0);
      point(pos.x+perpend.x, pos.y+perpend.y);
    }
    
  • Thank you both very much! I have yet to implement your code, but I worked it out on paper and I'm very impressed by the elegance of it! Didn't think of that as a way to get the perpendicular velocity vector.

    I am still a bit curious, however, as to why the calculation I did didn't work. Essentially I did the same calculation I did to the Particle's velocity vector, but using the amplitude instead of velocity and using the angle of the Particle + 90 degrees. Just wondering if anyone knows why that didn't work.

    Thank you for this solution! Going to try to implement it now!

  • edited September 2014

    Outta curiosity's sake, converted the example to http://p5js.org "mode":
    Very disappointed b/c I can't specify a whole RGB value & Vector there doesn't have a 3rd "target" parameter!

    // forum.processing.org/two/discussion/7103/
    // how-do-i-create-sinusoidal-movement-at-an-angle
    
    // by Hendeca, mods PhiLho & GoToLoop - 2014/Sep
    
    var VEL = 1.5, ANG = 60, AMP = 30, STEP = PI/12;
    var VEL_X = VEL*cos(ANG), VEL_Y = VEL*sin(ANG);
    var t = 0;
    
    var center  = createVector(), pos = createVector();
    var perpend = createVector();
    
    function setup() {
      createCanvas(600, 400);
      smooth(4).frameRate(60).strokeWeight(4).stroke(255);
      center.set(width, height*.75);
    }
    
    function draw() {
      pos.add(VEL_X, VEL_Y);
      if (pos.x<0 | pos.y<0)  pos.set(center);
    
      perpend.set(pos).sub(center)
        .set(-perpend.y, perpend.x)
          .setMag(AMP*sin(t += STEP));
    
      background(0);
      point(pos.x+perpend.x, pos.y+perpend.y);
    }
    
  • I'd say that your first problem was that you were trying to use degrees (60, 90) in the trig functions when they are expecting radians.

  • edited September 2014

    Just for completeness' sake, same code now in "CoffeeScript Mode": :>

    # forum.processing.org/two/discussion/7103/
    # how-do-i-create-sinusoidal-movement-at-an-ang
    
    # by Hendeca, mods PhiLho & GoToLoop - 2014/Sep
    
    
    VEL = 1.5; ANG = 60; AMP = 30; STEP = Processing::PI/12
    VEL_X = VEL*Math.cos ANG; VEL_Y = VEL*Math.sin ANG
    t = 0
    
    center  = new Processing::PVector; pos = new Processing::PVector
    perpend = new Processing::PVector
    
    
    setup: ->
    
      size 600, 400, JAVA2D; smooth 4; frameRate 60
      strokeWeight 4; stroke -1
    
      center.set width, height*.75, 0
    
    
    draw: ->
    
      pos.add VEL_X, VEL_Y, 0
      pos.set center  if pos.x<0 | pos.y<0
    
      perpend.set pos; perpend.sub center
      perpend.set -perpend.y, perpend.x, 0
      do perpend.normalize; perpend.mult AMP*sin t += STEP
    
      background 0
      point pos.x+perpend.x, pos.y+perpend.y
    
  • "for better performance"
    Very funny. :-)

    Anyway, good idea to use setMag in place of normalize() and mult() sequence.

  • edited September 2014

    HEHE! I still had to use normalize() + mult() in "CoffeeScript Mode".
    B/c the processing.js v1.4.1 it's based upon doesn't have setMag()! :(
    And neither p5js nor "JS & CS Modes" got PVector methods w/ a 3rd "target" parameter! X(

  • If I understand correctly your request, you must add an orthogonal vector to the current position of the vector.

    Thanks PhiLho! Your solution worked for me :] Very elegant! It makes a lot of sense and is much simpler than what I was doing before. Thanks also to GoToLoop for offering some changes and alternatives. Really appreciate your help! I got the sinusoidal movement working very quickly once I understood the concept of creating a perpendicular vector, normalizing it, and multiplying it by the velocity. This also works well with the code I had before in that I wasn't using a PVector for my velocity value but rather just a float value that can be applied to the angle of the particle.

    I haven't taken the time to try the other versions of the code that GoToLoop offered, but I'd like to look through them more when I finish my current project! Thank you!

  • edited September 2014

    I haven't taken the time to try the other versions of the code that GoToLoop offered,...

    For the p5js example, you can go to http://p5js.org/reference/, choose some of its reference functions,
    like http://p5js.org/reference/#/p5/alpha for example, click the "edit" button and paste the code there,
    replacing the original. Then click at "run" button and watch it working inside your browser! (*)

    For the CS latest example, you gotta install "CoffeeScript Mode" from Processing's IDE. Choose "Add Mode...".
    Select CS Mode and paste the code there. Make sure it's using a 2-space indentation.
    Press Run and your default browser will open up and run your CS code compiled already as JS,
    running from a local server provided by the IDE itself! :ar!

Sign In or Register to comment.