Jagged lines appearing in animating sine wave variation code

Wave w;

int noW = 5; // No. of Waves on either side of half period
int totalwaves = (noW*2)-1;
float freq = 1; // How many repetitions 
float period;

boolean inverse;

void setup() {
  size(800, 800);
  background(0);
  stroke(255);
  smooth();
  noFill();
  //noLoop();
  period  = height/freq ;  
  w = new Wave();
}

void draw() {
  background(0);
  translate(width/2, 0);
  w.calcWaves();
  w.display(); 
  w.resetWave();
}


class Wave {
  float halfper;
  float minperiod1, maxperiod1;
  float stdamp;
  float spacing;
  float angV; 
  // Height,period & angular frequency of wave in half period 
  float amp1, amp2;
  float per1, per2;
  float dx1, dx2;

  ArrayList<PVector[]> waves;
  float[] wavesPer; 

  Wave() {
    halfper = period/2;
    // Range of period to animate 
    minperiod1 = halfper - halfper*0.9;
    maxperiod1 = halfper + halfper*0.9;
    stdamp  = (halfper)*0.35;
    spacing = minperiod1/(noW-1);
    angV = spacing * 0.08;

    wavesPer = new float[totalwaves];
    resetWave();
    InitPer();
  }

  void resetWave() {
    waves = new ArrayList<PVector[]>();
  }

  void InitPer() {
    for (int i=0; i<totalwaves; i++) {
      per1 = minperiod1 + i*spacing;
      wavesPer[i] = per1;
    }  
  }

  void calcPer(int i) {
    per1 = wavesPer[i]+angV;   
    if (per1<=minperiod1 || per1>=maxperiod1) {
      angV = -angV;
    }
    wavesPer[i] = per1;    
    per2 = period - per1;
    dx1   = PI/(per1);
    dx2   = PI/(per2);
    amp1 = per1/(halfper) * stdamp;
    amp2 = per2/(halfper) * stdamp;
  }

  void calcWaves() {   
    for (int i=0; i<totalwaves; i++) {
      calcPer(i);
      float theta = 0;
      float x = 0;
      PVector[] tempV = new PVector[int(period+1)];
      for (int y=0; y<=period; y++) {
        if (y<=per1) {
          x = amp1 *  pow(sin(theta), 1);
          theta+=dx1;
        } else {
          x = amp2 *  pow(sin(theta), 1);
          theta+=dx2;
        }
        tempV[y] = new PVector(x, y);
      }
      waves.add(tempV);
      tempV = new PVector[int(period+1)]; // reset temp array
    }
  }


  void display() {
    for (int k=0; k<freq; k++) {
      for (int i=0; i<totalwaves; i++) {
        PVector[] tempV = waves.get(i);
        pushMatrix();
        translate(0, k*(period));
        beginShape();
        for (int j=0; j<tempV.length; j++) {
          vertex(tempV[j].x, tempV[j].y);
        } 
        endShape();
        popMatrix();
      }
    }
  }
}


This code implements sine wave with varying periods called per1 & per2 in the code. When wave is animating upwards, the amplitudes of per1 & per2 don’t seem to match up creating jagged lines whereas it plays out smoothly while animating downwards.
I can’t seem to figure the issue.

1 Like

Hello,

Sometimes I just start from scratch and rethink approach to a problem.

I wrote this quickly to see what I could do to achieve this effect:

// Sine wave modulation and phase shift
// v1.0.0
// GLV 2020-07-05

float x, y;

float phase;

void setup() 
 {
 size(640, 360);
 strokeWeight(2);
 }

void draw() 
  {
  background(0); 
    
  //phase shift
  phase += TAU/500;  
  
  float amp1 = 100;
  
  //modulate amp2
  float amp2 = 0.5 * sin(phase) + 0.5;
  
  for(int i = 0; i<width; i++)
    {
    int x = i;
    //sine wave
    float angle = TAU/ width;
    y = amp1*sin(i*angle + phase);
    stroke(255, 0, 0);
    point(x, y+height/2);
    
    //modulate sine wave (above)
    float angle2 = (TAU/2)/ width;
    float y2 = y*amp2*sin(i*angle2);
    stroke(0, 255, 0);
    point(x, y2+height/2);
    }

  //modulate amp2
  float amp3 = 0.8 * sin(phase) + 0.8;
  
  for(int i = 0; i<width; i++)
    {
    int x = i;
    //sine wave
    float angle = TAU/ width;
    y = amp1*sin(i*angle + phase);
    //point(x, y+height/2);
    
    //modulate sine wave (above)
    float angle2 = (TAU/2)/ width;
    float y2 = y*amp3*sin(i*angle2);
    
    stroke(255, 255, 0);
    point(x, y2+height/2);
    }  
  }

image

:)

2 Likes

@glv Thanks for the reply. I realized that the jagged lines are appearing not because of the code error but because of the way processing frames are animated.
From the code , as period1 gets too small the angular frequency dx = PI/ period gets too large causing long jumps in the wave resulting in mismatch of period1 wave and period2 wave.
As a cheat way of doing it, I am drawing the small period1 wave from bottom to top which solves the problem.

Wave w;

int noW = 7; // No. of Waves on either side of half period including half period
int totalwaves = (noW*2)-1; 
float freq = 2; // How many repetitions 
float period;

void setup() {
  size(1000, 1000);
  background(0);
  stroke(255);
  smooth();
  noFill();
  //noLoop();
  period  = height/freq ;  
  w = new Wave();
}

void draw() {
  background(0);
  pushMatrix();
  translate(width/2,0);
  //line(0,0,0,height);
  w.calcWaves();
  w.display(); 
  w.resetWaves();
  popMatrix();

} 

class Wave {
  float halfper;
  float minperiod1, maxperiod1;
  float stdamp;
  float spacing;
  float angV; 
  float range = 1;
  // Height,period & angular frequency of wave in half period 
  float amp1, amp2;
  float per1, per2;
  float dx1, dx2;
  ArrayList<PVector[]> waves;
  float[] wavesPer; 
  float angle = 0.0;
  float xoff = 0.0;
  Wave() {
    halfper = period/2;
    // Range of period to animate 
    minperiod1 = halfper - halfper*range;
    maxperiod1 = halfper + halfper*range;
    stdamp  = (halfper)*0.4;
    spacing = ((halfper - minperiod1)*0.45)/(noW-1);
    angV = spacing * 0.08;

    wavesPer = new float[totalwaves];
    resetWaves();
    InitPer();
  }

  void resetWaves() {
    waves = new ArrayList<PVector[]>();
  }

  void InitPer() {
    for (int i=0; i<totalwaves; i++) {
      per1 = minperiod1 + i*spacing;
      wavesPer[i] = per1;
    }
  }

  void calcPer(int i) {
    if (i==0) {
      per1 = wavesPer[i] + angV + (0.013/freq); // adding more velocity to first wave as it lags over a period of time.
    } else {
      per1 = wavesPer[i]+angV;
    }
    if (per1<=minperiod1 || per1>=maxperiod1) {
      angV = -angV;
    }
    wavesPer[i] = per1;    
    per2 = period - per1;
    //println("wavesPer["+i+"]: " +per1);
    //println("wavesPer["+i+"]: " +per2);
    dx1   = PI/(per1);
    dx2   = PI/(per2);
    //println("dx1: "+dx1, i);
    //println("dx2: " +dx2, i);
    amp1 = per1/(halfper) * stdamp;
    amp2 = per2/(halfper) * stdamp;
    //println("["+i+"]: " +amp1);
    //println("["+i+"]: " +amp2);
  }

  void calcWaves() {   
    angle += 0.004;
    for (int i=0; i<totalwaves; i++) {
      calcPer(i);
      float theta = 0.0;
      float x = 0.0;
      PVector[] tempV = new PVector[int(period+1)]; 
      if (per1<=halfper) {
        for (float y = period; y>=0; y--) {
          if (y<=per1) {
            x = amp1 *  pow(sin(theta), 1);
            theta+=dx1;
          } else {
            x = amp2 *  pow(sin(theta), 1);
            theta+=dx2;
          }
          tempV[int(y)] = new PVector(-x, y);
        }
      } else {
        for (int y=0; y<=period; y++) {
          if (y<=per1) {
            x = amp1 *  pow(sin(theta), 1);
            theta+=dx1;
          } else {
            x = amp2 *  pow(sin(theta), 1);
            theta+=dx2;
          }
          tempV[y] = new PVector(x, y);
        }
      }
      waves.add(tempV);
      tempV = new PVector[int(period+1)]; // reset temp array
    }
  }


  void display() {
    for (int k=0; k<freq; k++) {
      for (int i=0; i<totalwaves; i++) {
        PVector[] tempV = waves.get(i);
        pushMatrix();
        translate(0, k*(period)); 
        beginShape();
        for (int j=0; j<tempV.length; j++) {
          vertex(tempV[j].x, tempV[j].y);
        } 
        endShape();
        popMatrix();
      }
    }
  }
}

2 Likes

@Ruchi

Nice work!

:)

1 Like