Question

I have a piece of processing code that I was given, which appears to be setting up a randomized Fourier series. Unfortunately, despite my efforts to improve my mathematical skills, I have no idea what it is doing and the articles I have found are not much help.

I'm trying to extend this code so that I can draw a line tangent to a point on the slope created by the code bellow. The closest I can find to answering this is in the mathematics forum. Unfortunately, I don't really understand what is being discussed or if it really is relevant to my situation.

Any assistance on how I would go about calculating a tangent line at a particular point on this curve would be much appreciated.

UPDATE As of 06/17/13

I've been trying to play around with this, but without much success. This is the best I can do, and I doubt that I'm applying the derivative correctly to find the tangent (or even if I have found the derivative at the point correctly). Also, I'm beginning to worry that I'm not drawing the line correctly even if I have everything else correct. If anyone can provide input on this I'd appreciate it.

final int w = 800;
final int h = 480;
double[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
double[] derivatives;

void setup() {
  noStroke();
  size(w, h);
  fill(0,128,255);
  rect(0,0,w,h);
  int t[] = terrain(w,h);
  fill(77,0,0);
  for(int i=0; i < w; i++){
    rect(i, h, 1, -1*t[i]);
  }
  time = millis();
  timeDelay = 100;
  iter =0;
  img = get();
}

void draw() {
  int dnum = 0; //Current position of derivatives
  if(iter == numOfDeriv) iter = 0;
  if (millis() > time + timeDelay){
        image(img, 0, 0, width, height);
        strokeWeight(4);
        stroke(255,0,0);        
        point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
        strokeWeight(1);
        stroke(255,255,0);
        print("At x = ");
        print(iter);
        print(", y = ");
        print(skyline[iter]);
        print(", derivative = ");
        print((float)derivatives[iter]);
        print('\n');
        lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], 100);
        lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], -100);
        stroke(126);
        time = millis();
        iter += 1;
    }
}

void lineAngle(int x, int y, float angle, float length)
{
  line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}

int[] terrain(int w, int h){

    width = w;
    height = h;

    //min and max bracket the freq's of the sin/cos series
    //The higher the max the hillier the environment
    int min = 1, max = 6;

    //allocating horizon for screen width
    int[] horizon = new int[width];
    skyline =  new double[width];
    derivatives = new double[numOfDeriv];

    //ratio of amplitude of screen height to landscape variation
    double r = (int) 2.0/5.0;

    //number of terms to be used in sine/cosine series
    int n = 4;

    int[] f = new int[n*2];

    //calculating omegas for sine series
    for(int i = 0; i < n*2 ; i ++){
      f[i] = (int) random(max - min + 1) + min;
    }

    //amp is the amplitude of the series
    int amp =  (int) (r*height);
    int dnum = 0; //Current number of derivatives    
    for(int i = 0 ; i < width; i ++){
      skyline[i] = 0;
      double derivative = 0.0;
      for(int j = 0; j < n; j++){
         if(i % derivModBy == 0){
            derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) - 
                        sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
         }

        skyline[i] += ( sin( (f[j]*PI*i/height) ) +  cos(f[j+n]*PI*i/height) );
        }
      skyline[i] *= amp/(n*2);
      skyline[i] += (height/2);
      skyline[i] = (int)skyline[i];
      horizon[i] = (int)skyline[i];
      derivative *= amp/(n*2);
      if(i % derivModBy == 0){
        derivatives[dnum++] = derivative;
        derivative = 0;
      }
    }

    return horizon;
}

void reset() {
  time = millis();
}
Was it helpful?

Solution 2

I received an answer to this problem via "quarks" on processing.org form. Essentially the problem is that I was taking the derivative of each term of the series instead of taking the derivative of the sum of the entire series. Also, I wasn't applying my result correctly anyway.

Here is the code that quarks provided that definitively solves this problem.

final int w = 800;
final int h = 480;
float[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
float[] tangents;

public void setup() {
  noStroke();
  size(w, h);
  fill(0, 128, 255);
  rect(0, 0, w, h);
  terrain(w, h);
  fill(77, 0, 0);
  for (int i=0; i < w; i++) {
    rect(i, h, 1, -1*(int)skyline[i]);
  }
  time = millis();
  timeDelay = 100;
  iter =0;
  img = get();
}

public void draw() {
  if (iter == numOfDeriv) iter = 0;
  if (millis() > time + timeDelay) {
    image(img, 0, 0, width, height);
    strokeWeight(4);
    stroke(255, 0, 0);        
    point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
    strokeWeight(1);
    stroke(255, 255, 0);
    print("At x = ");
    print(iter);
    print(", y = ");
    print(skyline[iter]);
    print(", derivative = ");
    print((float)tangents[iter]);
    print('\n');
    lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], 100);
    lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], -100);
    stroke(126);
    time = millis();
    iter += 1;
  }
}

public void lineAngle(int x, int y, float angle, float length) {
  line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}

public void terrain(int w, int h) {      
  //min and max bracket the freq's of the sin/cos series
  //The higher the max the hillier the environment
  int min = 1, max = 6;
  skyline =  new float[w];
  tangents = new float[w];
  //ratio of amplitude of screen height to landscape variation
  double r = (int) 2.0/5.0;
  //number of terms to be used in sine/cosine series
  int n = 4;
  int[] f = new int[n*2];
  //calculating omegas for sine series
  for (int i = 0; i < n*2 ; i ++) {
    f[i] = (int) random(max - min + 1) + min;
  }
  //amp is the amplitude of the series
  int amp =  (int) (r*h);
  for (int i = 0 ; i < w; i ++) {
    skyline[i] = 0;
    for (int j = 0; j < n; j++) {
      skyline[i] += ( sin( (f[j]*PI*i/h) ) +  cos(f[j+n]*PI*i/h) );
    }
    skyline[i] *= amp/(n*2);
    skyline[i] += (h/2);
  }
  for (int i = 1 ; i < w - 1; i ++) {
    tangents[i] = atan2(skyline[i+1] - skyline[i-1], 2);
  }
  tangents[0] = atan2(skyline[1] - skyline[0], 1);
  tangents[w-1] = atan2(skyline[w-2] - skyline[w-1], 1);
}

void reset() {
  time = millis();
}

OTHER TIPS

Well it seems in this particular case that you don't need to understand much about the Fourier Series, just that it has the form:

    A0 + A1*cos(x) + A2*cos(2*x) + A3*cos(3*x) +... + B1*sin(x) + B2*sin(x) +...

Normally you're given a function f(x) and you need to find the values of An and Bn such that the Fourier series converges to your function (as you add more terms) for some interval [a, b].

In this case however they want a random function that just looks like different lumps and pits (or hills and valleys as the context might suggest) so they choose random terms from the Fourier Series between min and max and set their coefficients to 1 (and conceptually 0 otherwise). They also satisfy themselves with a Fourier series of 4 sine terms and 4 cosine terms (which is certainly easier to manage than an infinite number of terms). This means that their Fourier Series ends up looking like different sine and cosine functions of different frequencies added together (and all have the same amplitude).

Finding the derivative of this is easy if you recall that:

    sin(n*x)' = n * cos(x)
    cos(n*x)' = -n * sin(x)
    (f(x) + g(x))' = f'(x) + g'(x)

So the loop to calculate the the derivative would look like:

    for(int j = 0; j < n; j++){
        derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) - \
                        sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
    }

At some point i (Note the derivative is being taken with respect to i since that is the variable that represents our x position here).

Hopefully with this you should be able to calculate the equation of the tangent line at a point i.

UPDATE
At the point where you do skyline[i] *= amp/(n*2); you must also adjust your derivative accordingly derivative *= amp/(n*2); however your derivative does not need adjusting when you do skyline[i] += height/2;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top